0

以下に示すようなクエリがあります。

select count(test.id) from table1 
   inner join table2 on table1.id = table2.id
   where    (table2.email = 'test@gmail.com' 
   OR (table2.phone1 IS NOT NULL AND table2.phone1 in ('123456')) 
   OR (table2.phone2 IS NOT NULL AND table2.phone2 in ('1234456'))) 
   AND table2.id <> 1234 
   AND table2.created_at >= '2015-10-10' 
   AND table2.status NOT IN ('test') 
   AND table2.is_test = 'No';

table2.email、table2.phone1、table2.phone2、table2.created_at にインデックスがあります。これらはすべて単一インデックスであり、複合インデックスではありません。私の知る限り、(table2.email、table2.phone1、table2.phone2) の複合インデックスは、条件が OR 条件であるため機能しません。(table2.id、table2.created_at、table2.status、table2.is_test) に複合インデックスを作成しましたが、説明クエリで同じ結果が得られました。説明クエリを以下に示します

id  select_type table   type    possible_keys key     key_len ref rows Extra
 1  SIMPLE     table2   range   PRIMARY,     created_at  8        293  Using where
                                created_at,
                                email,
                                phone1,
                                phone2, 
                                com_index       
  1   SIMPLE    table1  eq_ref  PRIMARY       PRIMARY    4    id   1  Using index

ここで、com_index は私が作成した複合インデックスです。このクエリを高速化するためにインデックスを作成するにはどうすればよいですか。説明の結果から、クエリ用に選択されたキーは created_at のようです。テーブル 2 の複合インデックスを作成する方法はありますか? 私を助けてください。前もって感謝します。

編集:このクエリの生産について説明します:

+----+-------------+-------+--------+----------------------------------------------+---------+---------+----------------------+--------+-------------+
| id | select_type | table | type   | possible_keys                                | key     | key_len | ref                  | rows   | Extra       |
+----+-------------+-------+--------+----------------------------------------------+---------+---------+----------------------+--------+-------------+
|  1 | SIMPLE      | l0_   | range  | PRIMARY,created_at,email,day_phone,eve_phone | PRIMARY | 4       | NULL                 | 942156 | Using where |
|  1 | SIMPLE      | m1_   | eq_ref | PRIMARY                                      | PRIMARY | 4       | lead_platform.l0_.id |      1 | Using index |
+----+-------------+-------+--------+----------------------------------------------+---------+---------+----------------------+--------+-------------+
4

2 に答える 2

2

通常、MySQL は 3 つの列 (email、phone1、phone2) でインデックスを使用できません。

残りの条件はあまり具体的ではなく、本番データベースで優れた結果をもたらさないと思います(つまり、ほとんどの項目は「テスト」などではありません)。

OR複数の列にまたがるステートメントを使用してクエリを最適化するのは注意が必要です。

この記事では、このようなクエリを複数のクエリに分割するUNIONと、はるかに高速になることが示されています。あなたの場合、OR ステートメントを使用せずに 3 つのクエリを組み合わせたものになります。emailこのようにして、MySQL は、phone1およびのインデックスを使用してインデックス マージを実行できますphone2

テストして、実際のデータの方が速いかどうか教えてください。

SELECT COUNT(DISTINCT(t.id)) FROM (
    SELECT test.id FROM table1 
       INNER JOIN table2 on table1.id = table2.id
       WHERE table2.email = 'test@gmail.com' 
       AND table2.id <> 1234 
       AND table2.created_at >= '2015-10-10' 
       AND table2.status NOT IN ('test') 
       AND table2.is_test = 'No'

    UNION ALL 

    SELECT test.id FROM table1 
       INNER JOIN table2 on table1.id = table2.id
       WHERE table2.phone1 IS NOT NULL AND table2.phone1 in ('123456')
       AND table2.id <> 1234 
       AND table2.created_at >= '2015-10-10' 
       AND table2.status NOT IN ('test') 
       AND table2.is_test = 'No'

    UNION ALL   

    SELECT test.id FROM table1 
       INNER JOIN table2 on table1.id = table2.id
       WHERE table2.phone2 IS NOT NULL AND table2.phone2 in ('1234456')
       AND table2.id <> 1234 
       AND table2.created_at >= '2015-10-10' 
       AND table2.status NOT IN ('test') 
       AND table2.is_test = 'No') AS t
于 2016-11-01T21:00:46.077 に答える
1

列全体に配列を広げないでください。この場合、 に戻るリンクを含む電話番号の表を用意しますtable1。そのテーブルには、特定の table1 タイプの人に対して 0、1、2、またはそれ以上の数字があります。その場合、ORまたはUNIONは必要ありません。代わりに aJOINが必要です。

あなたは持っstatusていis_testます; これらは冗長に見えます。フラグがたくさんあっても役に立ちません。これらを組み合わせることができますか?

による検索の意味がわかりませんemail OR phone。両方ではなく、どちらか一方の値を持つようです。その場合、WHERE節 (and JOIN) を作成すると、for はありませんOR

結局のところINDEX(phone)、新しいテーブルINDEX(email)table1. status電子メールと電話はおそらく非常に選択的であるため、インデックスに など を追加しません。

于 2016-11-02T04:15:55.527 に答える