这是怎么回事。
The SELECT COUNT (...) icd_index where icd='25000'
将使用索引,该索引是与数据分开的BTree。但是它以这种方式扫描:
- 查找具有icd =‘25000’的第一个条目。这几乎是瞬时的。
- 向前扫描,直到找到icd的变化。这将仅扫描索引,而不接触数据。根据EXPLAIN,将有大约910,104个索引条目要扫描。
现在,让我们看一下该索引的BTree。根据索引中的字段,每行将恰好是22个字节,加上一些开销(估计为40%)。MyISAM索引块为1KB(参见InnoDB的16KB)。我估计每个块有33行。910,104
/
33说,要读取COUNT,需要读取大约27K块。(注意
COUNT(core_id)需要检查是否
core_id为空,
COUNT(*)不是这样;这是一个很小的差异。)在普通硬盘驱动器上读取27K块大约需要270秒。您很幸运能在60秒内完成。
第二次运行在key_buffer中找到了所有这些块(假设key_buffer_size至少为27MB),因此它不必等待磁盘。因此,它要快得多。(这将忽略查询缓存,您可以明智地刷新或使用SQL_NO_CACHE。)
5.6恰好无关紧要(但是感谢您提及它),因为此过程自4.0或更低版本以来没有更改(除了utf8不存在;更多内容请参见下文)。
切换到InnoDB可以通过两种方式提供帮助。主键将与数据“聚集”在一起,而不是存储为单独的BTree。因此,一旦数据或PK被缓存,另一个立即可用。块的数量将更像是5K,但它们将是16KB块。如果高速缓存很冷,这些文件可能会更快地加载。
您问“我是否需要一个单独的icd索引?”-那么这会使MyISAM
BTree的大小缩小到每行约21个字节,因此BTree的大小约为21/27倍,没有太大的改进(至少对于冷缓存情况)。
另一个想法是, 如果
icd始终是数字且始终是数字,则使用
MEDIUMINTUNSIGNED,
ZEROFILL如果它可以有前导零,则继续使用。
糟糕,我没注意到字符集。(我已经固定了上面的数字,但让我详细说明。)
- CHAR(5)允许5个 字符 。
- ascii每个 字符 占用1 个字节 。 __
- utf8每个 字符 最多占用3 个字节 。 __
- 因此,CHAR(5)CHARACTER SET utf8 始终 占用15 个字节 。 __
将列更改为
CHAr(5) CHARACTER SET ascii会将其缩小到5个字节。
将其更改为MEDIUMINT UNSIGNED ZEROFILL会将其缩小为3个字节。
缩小数据将使I / O速度大致成比例(在另外两个字段中再允许6个字节之后)。



