如果我创建以下两个标记
ALTER TABLE requests ADD INDEX daily_ips(exec_date, ip_address);
ALTER TABLE requests ADD INDEX is_cached(exec_date, cached);
show index from requests
的输出如下
Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment
requests 1 daily_ips 1 exec_date A 413 NULL NULL YES BTREE
requests 1 daily_ips 2 ip_address A 218334 NULL NULL YES BTREE
requests 1 is_cached 1 exec_date A 165 NULL NULL YES BTREE
requests 1 is_cached 2 cached A 165 NULL NULL YES BTREE
我有以下查询
EXPLAIN SELECT exec_date,
100 * SUM(CASE WHEN cached = 'no' THEN 1 ELSE 0 END) / SUM(1) cached_no,
100 * SUM(CASE WHEN cached != 'no' THEN 1 ELSE 0 END) / SUM(1) cached_yes
FROM requests
GROUP BY exec_date;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE requests index NULL daily_ips 263 NULL 436695
但是我想强制查询优化器使用is_cached
索引而不是daily_ips
索引。
如果我删除daily_ips
索引并再次添加
ALTER TABLE requests DROP INDEX daily_ips;
ALTER TABLE requests ADD INDEX daily_ips(exec_date, ip_address);
然后运行相同的EXPLAIN
语句,查询优化器选择is_cached
索引。
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE requests index NULL is_cached 6 NULL 440493 Using index
查询优化器是否期望根据添加的顺序选择索引?
如何告诉查询优化器使用哪个索引?
答案 0 :(得分:2)
您可以指定查询运行哪个索引sholud。
试试这个:
EXPLAIN SELECT exec_date,
100 * SUM(CASE WHEN cached = 'no' THEN 1 ELSE 0 END) / SUM(1) cached_no,
100 * SUM(CASE WHEN cached != 'no' THEN 1 ELSE 0 END) / SUM(1) cached_yes
FROM requests USE INDEX(is_cached)
GROUP BY exec_date;
USE INDEX
和FORCE INDEX
之间的差异:
通过指定USE INDEX(index_list),您可以告诉MySQL只使用其中一个命名索引来查找表中的行。替代语法IGNORE INDEX(index_list)可用于告诉MySQL不使用某些特定索引或索引。如果EXPLAIN显示MySQL正在使用可能索引列表中的错误索引,则这些提示很有用。
您还可以使用FORCE INDEX,其作用类似于USE INDEX(index_list),但另外还假设表扫描非常昂贵。换句话说,只有在无法使用某个给定索引查找表中的行时才使用表扫描。
<强>更新强>
尝试此查询:
SELECT exec_date,
100 * SUM(IF(cached = 0, 1, 0)) / SUM(1) cached_no,
100 * SUM(IF(cached = 1, 1, 0)) / SUM(1) cached_yes
FROM (SELECT exec_date, IF(cached = 'no', 0, 1) cached
FROM requests GROUP BY exec_date) AS A
答案 1 :(得分:2)
要强制使用一个索引,您可以使用FORCE INDEX
指令:
EXPLAIN SELECT exec_date,
100 * SUM(CASE WHEN cached = 'no' THEN 1 ELSE 0 END) / SUM(1) cached_no,
100 * SUM(CASE WHEN cached != 'no' THEN 1 ELSE 0 END) / SUM(1) cached_yes FROM requests FORCE INDEX(`is_cached`) GROUP BY exec_date;
MySQL优化器选择索引,返回较少的行进行扫描,在这种情况下,这两个索引的计数非常接近(436695对比440493)。