2016-11-22 32 views
2

私はjob_titledomainと呼ばれる列を持つ従業員のテーブル(約450万)を持っています。選択クエリを改善してより速くするにはどうすればよいですか?

動的なクエリを作成して実行して、役職に基づいて特定の従業員を選択し、提供されるドメインの配列内にあるドメインを希望することができます。

  1. 役職彼らが望む:、彼らは2つのものを入力してください - それはどのように動作する

    は、フロントエンドのユーザーが(10,000どこでも200から)ドメインの大きさの配列で終わりです

    は、ジョブのタイトルは、彼らがだから私たちは、このように見える終わるクエリを作成

を除外したい

  • を含ま
    SELECT employee_id 
    FROM employee 
    WHERE (
         domain LIKE '%shetlandfoods.co.uk' 
         OR domain LIKE '%example1.co.uk' 
         OR domain LIKE '%example2.co.uk' 
    
         -- About 50 additional domains in this list 
    
         OR domain LIKE '%example50.co.uk' 
        ) 
        AND (job_title LIKE '%Manager%' OR job_title LIKE '%Director%') 
        AND (job_title NOT LIKE '%Assistant%') 
    

    (ドメインのリストが非常に長く、ドメイン(何千ものを含んでいてもよいこと注意!)は)

    さて、このようなクエリは約230秒かかり、それは約180でのみですドメイン!何千ということを想像してみてください。それは永遠にかかります。

    このクエリを最適化/変更してより高速に実行できる方法があるのだろうかと思っていましたか?あるいは、私がデータベースにできることは何ですか?

  • +0

    その後、 'そのほとんどがちょうどドメイン、これだけ最後までスキップされているこの

    SELECT employee_id FROM employee WHERE INSTR(domain,'shetlandfoods.co.uk') > 0

    を試すことができますが、別のを試すことができます一つの選択肢であります'これらの索引付けされていないLIKEフィルタはおそらく問題です。 –

    +0

    'domain'データのソースは何ですか?また、いくつかのサンプルを表示できますか?私の考えは、多分このデータを何らかの形で前処理してクエリを簡単にすることができるということです。 –

    +0

    Pro-tip:SQLに改行を含めることができます;-) –

    答えて

    3

    ここには2つのオプションがあります(上記の@paulで提案されている2番目のコメント)。

    1つは、domain列のデータをあらかじめ処理して、正確なドメインのみを持つようにすることです。これはよく知られた問題であり、JavaまたはJavaScriptでの処理は比較的簡単です。これが行われた場合は、domain列に索引をつけて、次のようなものを見WHERE句を使用することができます。

    WHERE domain IN ('shetlandfoods.co.uk', 
           'alac.shetland.co.uk', 
           'malakofflimited.co.uk', 
           ...) 
    

    別のオプションは、用語の逆に対してドメインの逆を比較することであるかもしれないがあなたは元のWHERE句に入っていました。

    WHERE REVERSE(domain) LIKE 'ku.oc.sdoofdnaltehs%' OR 
         REVERSE(domain) LIKE 'ku.oc.dnaltehs.cala%' OR 
         REVERSE(domain) LIKE 'ku.oc.detimilffokalam%' OR 
         ... 
    

    あなたはWHERE句の各用語のための逆を計算するためのMySQLを強制する必要はありませんように、あなたも、あなたのアプリケーション/ UI層からdomainの逆を格納することができます。

    MySQLを起動する前にドメインを抽出するための帯域幅があると仮定すると、最初のオプションに向かって傾けるかもしれません。

    +1

    ** REVERSE(ドメイン)**はこれを行う最善の方法ではありません。 ** REVERSE(ドメイン)**値を新しいフィールドに格納する方がはるかに優れています。あなたはインデックスを使うことができます。あなたのケースでは、常に完全なテーブルスキャン –

    +0

    私は同じ名前の 'domain'と' job_title'の両方にインデックスを持っています。 – ThePerplexedOne

    +0

    @BerndBuffen私は、MySQLの外部とは逆の計算と格納を提案しました。私はアプリ層で真のドメインを抽出することをお勧めします。そしてこの場合、インデックスは物事をスピードアップすべきです。 –

    0

    シナリオのこの種のために次のように、一時テーブルを作成することができます。

    逆転
    SELECT e.employee_id FROM employee e JOIN domain_values d ON (e.domain LIKE d.domain_value) AND 
        (e.job_title LIKE '%Manager%' OR e.job_title LIKE '%Director%') AND (e.job_title NOT LIKE '%Assistant%'); 
    
    +0

    そうすることのメリットは何ですか? – ThePerplexedOne

    +0

    これは上記よりも効率的です。 –

    0

    :として選択し

    INSERT INTO domain_values VALUES ('%shetlandfoods.co.uk'), ('%shopshetlandtoday.co.uk'), ........; 
    

    CREATE TEMPORARY TABLE domain_values (
        domain_value VARCHAR(100) 
    ); 
    

    次にとしてすべてのドメインを挿入テキストのように

    WHERE REVERSE(domain) LIKE 'ku.oc.sdoofdnaltehs%' OR REVERSE(domain) LIKE 'ku.oc.dnaltehs.cala%' OR REVERSE(domain) LIKE 'ku.oc.detimilffokalam%'...

    あなたも、これは速くLIKE %text%

    関連する問題