18

MySQLに2つのインデックスを使用させようとしています。テーブルを結合していて、2つのインデックス間のクロスを利用したいと思います。具体的な用語は「intersectの使用」であり、MySQLドキュメントへのリンクは次のとおりです。

http://dev.mysql.com/doc/refman/5.0/en/index-merge-optimization.html

この実装を強制する方法はありますか?私のクエリはそれを使用していました(そしてそれはものをスピードアップしました)が、今は何らかの理由でそれが停止しました。

これが私がやりたいJOINです。クエリで使用する2つのインデックスは、scs.CONSUMER_ID_1とscs_CONSUMER_ID_2です。

JOIN survey_customer_similarity AS scs
    ON cr.CONSUMER_ID=scs.CONSUMER_ID_2 
    AND cal.SENDER_CONSUMER_ID=scs.CONSUMER_ID_1 
    OR cr.CONSUMER_ID=scs.CONSUMER_ID_1 
    AND cal.SENDER_CONSUMER_ID=scs.CONSUMER_ID_2
4

2 に答える 2

22

MySQLDocsを参照してくださいFORCE INDEX

JOIN survey_customer_similarity AS scs 
FORCE INDEX (CONSUMER_ID_1,CONSUMER_ID_2)
ON
cr.CONSUMER_ID=scs.CONSUMER_ID_2 
AND cal.SENDER_CONSUMER_ID=scs.CONSUMER_ID_1 
OR cr.CONSUMER_ID=scs.CONSUMER_ID_1 
AND cal.SENDER_CONSUMER_ID=scs.CONSUMER_ID_2

TheScrumMeisterが以下で指摘しているように、2つのインデックスを実際に同時に使用できるかどうかは、データによって異なります。


クエリの実行と交差を制御するために、テーブルを2回表示する必要がある例を次に示します。

これを使用して、100Kを超えるレコードを含むテーブルを作成します。この場合、約1K行がフィルターi in (2,3)に一致し、1K行が次のように一致しj in (2,3)ます。

drop table if exists t1;
create table t1 (id int auto_increment primary key, i int, j int);
create index ix_t1_on_i on t1(i);
create index ix_t1_on_j on t1(j);
insert into t1 (i,j) values (2,2),(2,3),(4,5),(6,6),(2,6),(2,7),(3,2);
insert into t1 (i,j) select i*2, j*2+i from t1;
insert into t1 (i,j) select i*2, j*2+i from t1;
insert into t1 (i,j) select i*2, j*2+i from t1;
insert into t1 (i,j) select i*2, j*2+i from t1;
insert into t1 (i,j) select i*2, j*2+i from t1;
insert into t1 (i,j) select i*2, j*2+i from t1;
insert into t1 (i,j) select i*2, j*2+i from t1;
insert into t1 (i,j) select i*2, j*2+i from t1;
insert into t1 (i,j) select i*2, j*2+i from t1;
insert into t1 (i,j) select i*2, j*2+i from t1;
insert into t1 (i,j) select i*2, j*2+i from t1;
insert into t1 (i,j) select i*2, j*2+i from t1;
insert into t1 (i,j) select i, j from t1;
insert into t1 (i,j) select i, j from t1;
insert into t1 (i,j) select 2, j from t1 where not j in (2,3) limit 1000;
insert into t1 (i,j) select i, 3 from t1 where not i in (2,3) limit 1000;

行うとき:

select t.* from t1 as t where t.i=2 and t.j=3 or t.i=3 and t.j=2

正確に8つの一致が得られます:

+-------+------+------+
| id    | i    | j    |
+-------+------+------+
|     7 |    3 |    2 |
| 28679 |    3 |    2 |
| 57351 |    3 |    2 |
| 86023 |    3 |    2 |
|     2 |    2 |    3 |
| 28674 |    2 |    3 |
| 57346 |    2 |    3 |
| 86018 |    2 |    3 |
+-------+------+------+

EXPLAIN上記のクエリで使用して、以下を取得します。

id | select_type | table | type  | possible_keys         | key        | key_len | ref  | rows | Extra
1  | SIMPLE      | t     | range | ix_t1_on_i,ix_t1_on_j | ix_t1_on_j | 5       | NULL | 1012 | Using where

FORCE INDEX2つのインデックスのクエリに追加しても、まったく同じものEXPLAINが返されます。

2つのインデックスにまたがって収集し、それらを交差させるには、次を使用します。

select t.* from t1 as a force index(ix_t1_on_i)

join t1 as b force index(ix_t1_on_j) on a.id=b.id

where a.i=2 and b.j=3 or a.i=3 and b.j=2

でそのクエリを使用して、explain以下を取得します。

id | select_type | table | type  | possible_keys | key        | key_len | ref  | rows | Extra
1  | SIMPLE      | a     | range | ix_t1_on_i    | ix_t1_on_i | 5       | NULL | 1019 | Using where
1  | SIMPLE      | b     | range | ix_t1_on_j    | ix_t1_on_j | 5       | NULL | 1012 | Using where; Using index

これは、インデックスが使用されていることを示しています。しかし、他の多くの要因に応じて、それが速くなる場合とそうでない場合があります。

于 2011-01-30T03:58:31.900 に答える
1

MySQLは、結合ごとに1つのインデックスの使用のみをサポートします。結合のインデックスとして2つの列を使用する場合は、これらの2つの列に1つのインデックスを作成する必要があります。(a、b)のインデックスは、aだけのインデックスとしても機能するため、これは見た目ほど悪くはないことに注意してください。

MySQLのマニュアルを参照してください

列がインデックスの左端のプレフィックスを形成していない場合、MySQLはインデックスを使用できません。

于 2011-01-30T07:28:21.210 に答える