gpt4 book ai didi

当来自不同表的字段处于 OR 条件时,MySQL 不使用索引

转载 作者:行者123 更新时间:2023-11-29 02:01:18 27 4
gpt4 key购买 nike

看到这个:Can you use index in mysql using "col1 OR col2"?但我想我可以问这个相关问题以使讨论简单明了。

我有两个表:listsagree_and_disagree_count

lists 表有两个 timestamp 字段 modified_onfirst_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 的评论。

最佳答案

一旦 list_id 上的 JOIN 正在进行,MySQL 就无法将列表标识符与查询中使用并保存在索引中的字段“链接”,因为没有索引包含两者 ID 那些字段;并且您不能对索引运行连接。

尝试创建这两个索引:

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 重试。在我的系统上,我尝试创建两个最小表,每个表有两条记录:

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?

关于当来自不同表的字段处于 OR 条件时,MySQL 不使用索引,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14204651/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com