2

これを見た:「col1ORcol2」を使用してmysqlでインデックスを使用できますか? しかし、議論を単純かつ的確に保つために、この関連する質問をすることができると思いました。

私は2つのテーブルを持っています:listsagree_and_disagree_count

listsテーブルには2つのtimestampフィールドmodified_onとがありfirst_publish_dateます。これらのフィールドには両方とも独自のインデックスがあります。

agree_and_disagree_countテーブルにはtimestampフィールドもありdate_created、これもインデックスが付けられます。

同じテーブルのフィールドに関する次のORステートメントでは、両方のインデックスが使用されます。

mysql>  EXPLAIN SELECT * FROM lists l
    ->  WHERE (l.modified_on > '2013-01-07 12:50:51' OR
    ->   l.first_publish_date > '2013-01-07 12:50:51')\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: l
         type: index_merge
possible_keys: modifiedon,first_publish_date
          key: modifiedon,first_publish_date
      key_len: 4,9
          ref: NULL
         rows: 2
        Extra: Using sort_union(modifiedon,first_publish_date); Using where

ただし、フィールドが異なるテーブルからのものである場合、インデックスは使用されていないように見えます。

mysql> EXPLAIN SELECT * FROM lists l
    -> JOIN agree_and_disagree_count adc ON adc.list_id=l.list_id
    -> WHERE (l.modified_on > '2013-01-07 12:50:51' OR
    -> adc.date_created > '2013-01-07 12:50:51')\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: adc
         type: ALL
possible_keys: list_id_type_id,idx_list_id,idx_date_created
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 5114907
        Extra:
*************************** 2. row ***************************
           id: 1
  select_type: SIMPLE
        table: l
         type: eq_ref
possible_keys: PRIMARY,modifiedon
          key: PRIMARY
      key_len: 4
          ref: adc.list_id
         rows: 1
        Extra: Using where

なんで?


コメントに適切にフォーマットされた返信を入力する方法がわからないので、以下は私を助けてくれた@Iserniへの返信です。

私は次のことをしました:

use test;

-- create tables
create table lists (
list_id INT UNSIGNED NOT NULL AUTO_INCREMENT,
modified_on TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
first_publish_date DATETIME NULL DEFAULT NULL,
primary key (list_id)
) ENGINE=InnoDB;

create table agree_and_disagree_count (
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
list_id int unsigned not null,
date_created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
primary key (id)
) ENGINE=InnoDB;

-- create indices
create index index_modified_on on lists (modified_on);
create index index_first_publish_date on lists (first_publish_date);

create index index_data_created on agree_and_disagree_count (date_created);

-- load data
insert into lists (list_id, modified_on, first_publish_date) values 
(1, now(), now()),
(2, now(), now()),
(3, now(), now());

insert into agree_and_disagree_count (list_id, date_created) values 
(1, now()), (1, now()), (2, now());

-- query
EXPLAIN SELECT * FROM lists l JOIN agree_and_disagree_count adc 
ON adc.list_id=l.list_id WHERE (l.modified_on > '2013-01-01 12:50:51'
OR adc.date_created > '2013-01-07 11:50:51');

+----+-------------+-------+------+----------------------------------+------+---------+------+------+--------------------------------+
| id | select_type | table | type | possible_keys                    | key  | key_len | ref  | rows | Extra                          |
+----+-------------+-------+------+----------------------------------+------+---------+------+------+--------------------------------+
|  1 | SIMPLE      | l     | ALL  | PRIMARY,index_modified_on        | NULL | NULL    | NULL |    3 |                                |
|  1 | SIMPLE      | adc   | ALL  | index_data_created,index_list_id | NULL | NULL    | NULL |    3 | Using where; Using join buffer |
+----+-------------+-------+------+----------------------------------+------+---------+------+------+--------------------------------+

-- create new indexes suggested by Iserni
CREATE INDEX adc_test_ndx ON agree_and_disagree_count (list_id, date_created);
CREATE INDEX l_test_ndx ON lists (list_id, modified_on);

-- query
EXPLAIN SELECT * FROM lists l JOIN agree_and_disagree_count adc 
ON adc.list_id=l.list_id WHERE (l.modified_on > '2013-01-01 12:50:51'
OR adc.date_created > '2013-01-07 11:50:51');

+----+-------------+-------+-------+-----------------------------------------------+--------------+---------+------+------+--------------------------------+
| id | select_type | table | type  | possible_keys                                 | key          | key_len | ref  | rows | Extra                          |
+----+-------------+-------+-------+-----------------------------------------------+--------------+---------+------+------+--------------------------------+
|  1 | SIMPLE      | adc   | index | index_data_created,index_list_id,adc_test_ndx | adc_test_ndx | 8       | NULL |    3 | Using index                    |
|  1 | SIMPLE      | l     | ALL   | PRIMARY,index_modified_on,l_test_ndx          | NULL         | NULL    | NULL |    3 | Using where; Using join buffer |
+----+-------------+-------+-------+-----------------------------------------------+--------------+---------+------+------+--------------------------------+

フルスキャンがまだ行われているように見えますか?


受け入れられた回答の下にある@Iserniのコメントを見てください。

4

1 に答える 1

3

JOINオンが進行中の場合、MySQLはリスト識別子をクエリで使用されインデックスに保存されたフィールドに「リンク」する方法がありません。IDそれらのフィールドの両方list_idを含むインデックスがないためです。インデックスで結合を実行することはできません。

次の2つのインデックスを作成してみてください。

CREATE INDEX adc_test_ndx ON agree_and_disagree_count (list_id, date_created);
CREATE INDEX l_test_ndx ON lists (list_id, modified_on);

EXPLAINで再試行します。私のシステムでは、それぞれ2つのレコードを持つ2つの最小テーブルを作成しようとしました。

mysql> EXPLAIN SELECT * FROM lists l JOIN agree_and_disagree_count adc 
ON adc.list_id=l.list_id WHERE (l.modified_on > '2013-01-01 12:50:51'
OR adc.date_created > '2013-01-07 11:50:51')\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: l
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 2
        Extra:
*************************** 2. row ***************************
           id: 1
  select_type: SIMPLE
        table: adc
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 2
        Extra: Using where; Using join buffer
2 rows in set (0.00 sec)

その後:

mysql> CREATE INDEX adc_test_ndx ON agree_and_disagree_count (list_id, date_created);
Query OK, 0 rows affected (0.00 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> CREATE INDEX l_test_ndx ON lists (list_id, modified_on);
Query OK, 0 rows affected (0.00 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> EXPLAIN SELECT * FROM lists l JOIN agree_and_disagree_count adc 
ON adc.list_id=l.list_id WHERE (l.modified_on > '2013-01-01 12:50:51'
OR adc.date_created > '2013-01-07 11:50:51')\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: l
         type: index
possible_keys: l_test_ndx
          key: l_test_ndx
      key_len: 9
          ref: NULL
         rows: 2
        Extra: Using index
*************************** 2. row ***************************
           id: 1
  select_type: SIMPLE
        table: adc
         type: ref
possible_keys: adc_test_ndx
          key: adc_test_ndx
      key_len: 5
          ref: test.l.list_id
         rows: 1
        Extra: Using where; Using index
2 rows in set (0.00 sec)

mysql>

予想どおり、両方のテーブルでインデックスを作成しています。

テーブルの構造と既存のインデックス、さらにはSQLFiddleを投稿できますか?

于 2013-01-07T22:05:05.707 に答える