Rol*_*DBA 12
即使基数很高,MySQL 查询优化器使用的临界点还是密钥分发或存储引擎。
回到 2012 年 11 月 13 日,我讨论了不平衡的键如何使查询优化器选择不同的索引(有时根本不选择和索引):索引必须覆盖所有选定的列才能用于 ORDER BY?
在那篇文章中,我加载了一个表调用mf
(男性女性)并存储了性别M
或F
. 我插入了 37 Ms 和 3F。然后我运行了解释与 MyISAM 和 InnoDB 交叉的男性和女性值的计划。这些键和存储引擎的选择产生了一些有趣的结果。
您需要做的是检查您的密钥的分布(或不平衡)情况。
您需要运行以下两个查询
SELECT IFNULL(source,'Total'),COUNT(1) RowCount
FROM tbl GROUP BY source WITH ROLLUP;
SELECT IFNULL(state,'Total'),COUNT(1) RowCount
FROM tbl GROUP BY state WITH ROLLUP;
Run Code Online (Sandbox Code Playgroud)
这将为您提供每个值的计数以及总行数。
在我之前的帖子中,我说过我使用 5% 的经验法则。查看每个值的行数。如果任何特定源或状态的行数超过表行数的 5%,查询优化器将在总线下抛出一个索引并尝试另一个索引。在极少数情况下,它可能只是做一次全表扫描。
如果任何具有低行数的键不能产生良好的索引选择,您可能需要重新计算 MyISAM 表的索引统计信息(特别是如果 MyISAM 表经历了大量 INSERT、UPDATE 和 DELETE,从而使索引统计信息过时) . 只需运行这个:
ANALYZE TABLE tbl;
Run Code Online (Sandbox Code Playgroud)
或者要对 MyISAM 表进行碎片整理并重新计算索引统计信息,请运行
OPTIMIZE TABLE tbl;
Run Code Online (Sandbox Code Playgroud)
我喜欢 Alexandros (+1 for you) 发布的答案。
我想通过他的回答更新和扩展我的解释。
您提到了以下基数
state
有 22source
有 1122既然如此,就需要运行以下命令
ALTER TABLE tbl DROP INDEX state;
ALTER TABLE tbl ADD INDEX state_source_index (state,source);
Run Code Online (Sandbox Code Playgroud)
不要颠倒列的顺序。您应该始终首先索引较低基数的列。
好的,创建该索引将使您的查询变得更好。或者,会吗???
创建索引后,请运行此查询
SELECT
IF(ISNULL(state)=1,'Total',
CONCAT('Total Sources for ',state)) Statistic,RowCount
FROM
(
SELECT state,source COUNT(1) RowCount
FROM tbl GROUP BY state,source WITH ROLLUP
) A;
Run Code Online (Sandbox Code Playgroud)
这将为您提供(state,source)
表中所有组合键的计数以及每个州的小计。任何RowCount
超过该表的5%的任意组合键将最有可能导致表扫描。
你的最后一条评论是
我从你的回答中学到了很多。谢谢你。当键和多列键不平衡时,您会建议什么策略?我不明白为什么我应该先索引较低的基数列?
根据您需要的查询类型,列的顺序将有所帮助。
如果你运行这样的查询
SELECT ... FROM tbl ORDER BY state,source;
SELECT ... FROM tbl WHERE state='NY' ORDER BY source;
SELECT source,COUNT(1) RowCount FROM tbl WHERE state='NY' GROUP BY source;
那么,索引应该是 (state,source)
如果你运行这样的查询
SELECT ... FROM tbl ORDER BY source,state;
SELECT ... FROM tbl WHERE source='blog' ORDER BY state;
SELECT state,COUNT(1) RowCount FROM tbl WHERE source='blog' GROUP BY state;
那么,索引应该是(source,state)
。
我通常首先使用具有较低基数的列行,以使索引扫描更顺畅,以便在 ORDER BY 或 GROUP BY 以及其他列中涉及较低基数的查询。
如果您对索引(state,source)
不满意,您可以同时制作
ALTER TABLE tbl ADD INDEX state_source_index (state,source);
ALTER TABLE tbl ADD INDEX source_state_index (source,state);
Run Code Online (Sandbox Code Playgroud)
对您的查询运行 EXPLAIN 计划,看看哪个索引被更频繁地使用。
无论键组合如何不平衡,无论列在复合索引中的顺序如何,如果使用的列按组编入索引,则评估数据的范围和顺序会更快。
如果每个(source,state)
组合键都需要按 排序date
,则需要将该date
列合并到索引中作为最后一列。
ALTER TABLE tbl ADD INDEX state_source_date_index (state,source,date);
ALTER TABLE tbl ADD INDEX source_state_date_index (source,state,date);
Run Code Online (Sandbox Code Playgroud)
这样就ORDER BY
不必触发排序。