表格示例:
id | source | removed
17D30437329A9B9 | | 0
M851X0LG81045F | 17D30437329A9B9 | 0
QQG1RU1M8E5JHO | | 0
QDVHFNFKF0Z80W | 17D30437329A9B9 | 0
8BEFSFGUPBXJHV | | 0
当我查询时:
SELECT *
FROM `uploads`
WHERE (id = '17D30437329A9B9 ' OR `source` = '17D30437329A9B9 ')
AND removed = 0
查询需要大约25秒(我有大约1700万行)。
但是当我跑这个时:
SELECT *
FROM `uploads`
WHERE (id = '17D30437329A9B9 ' OR `source` = '17D30437329A9B9 ')
或者这个:
SELECT *
FROM `uploads`
WHERE (`id` = '17D30437329A9B9 ')
AND removed = 0
或那:
SELECT *
FROM `uploads`
WHERE (`source` = '17D30437329A9B9 ')
AND removed = 0
查询运行得很快。
为什么第一个查询运行速度很慢,我该如何解决?
编辑:
EXPLAIN SELECT * FROM uploads WHERE (id = '17D30437329A9B9 ' OR source = '17D30437329A9B9 ') AND removed = 0;
的结果:
+----+-------------+---------+------+-------------------------------------------------------+---------+---------+-------+---------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+------+-------------------------------------------------------+---------+---------+-------+---------+-------------+
| 1 | SIMPLE | uploads | ref | PRIMARY,removed,source,idx_member_selectFiles,id,id_2 | removed | 1 | const | 8829521 | Using where |
+----+-------------+---------+------+-------------------------------------------------------+---------+---------+-------+---------+-------------+
答案 0 :(得分:1)
似乎没有复合索引。
运行此操作并再试一次
创建复合INDEX
ALTER TABLE `uploads`
ADD KEY (`id`,`source`,`removed`);
如果有效,请告诉我。
答案 1 :(得分:0)
具有OR
条件的查询的MySQL执行计划有时不是最佳的。
我建议您重新编写查询以合并来自两个单独查询的结果。
SELECT u1.*
FROM `uploads` u1
WHERE u1.id = '17D30437329A9B9 '
AND u1.removed = 0
UNION ALL
SELECT u2.*
FROM `uploads` u2
WHERE u2.source = '17D30437329A9B9 '
AND u2.removed = 0
AND NOT (u2.id <=> '17D30437329A9B9 ')
每个SELECT都可以有效地使用最合适的索引。
第一个SELECT可以使用带有id
前导列的索引。第二个SELECT可以使用带有source
前导列的索引。
后续
问:如果我使用IN?喜欢WHERE(id IN('a','b')或来源IN('a','b'))AND删除= 0答:我会使用相同的方法。
SELECT u1.*
FROM `uploads` u1
WHERE u1.id IN ('17D30437329A9B9 ', ... )
AND u1.removed = 0
UNION ALL
SELECT u2.*
FROM `uploads` u2
WHERE u2.source IN ('17D30437329A9B9 ', ... )
AND u2.removed = 0
AND ( u2.id IS NULL OR u2.id NOT IN ('17D30437329A9B9 ', ... ) )
第二个SELECT上的最后一个条件是为了防止查询返回第一个SELECT已经返回的行。
使用NOT IN,只需确定列表中的值 none 为NULL。 (如果NOT IN列表包含NULL值,则没有行满足条件。)
如果id
中的uploads
列保证为NOT NULL,则可以消除对NULL的检查。 (我们没有看到任何表定义,因此我们无法判断id
是否被定义为NOT NULL,因此编写查询以在更一般的情况下工作,而不是基于可能错误的假设。)
答案 2 :(得分:0)
B-Tree索引对于基数较低的列不好。在你的情况下,MySQL选择列removed
的索引非常糟糕,因为只存在两个不同的值。
我怀疑永远不会在removed
上看到索引的好处。删除removed
上的索引。
位图索引而不是B树索引会很好。据我所知,MySQL不支持Bitmap-Indexes。
此外,(id, source)
上的索引在这种情况下会有所帮助。