mysql - 在索引列上计算行数比在主列和普通列上慢?
问题描述
我想知道为什么会发生这种情况?我有一个简单的表,其中包含一个主键Id
列、一个索引列A
和一些其他普通列(of datetime
),并且所有字段都具有非空值。
当我尝试像这样计算主键列上的行数时:
select count(Id) from my_table
返回值大约需要 0.4 秒(总共大约 1.1M 条记录)。
我尝试了相同的查询,但对于普通(datetime
如前所述)列,它几乎需要相同的时间(实际上有点慢)。但是当我在索引列上尝试相同的查询时A
,最多需要 1.2 秒才能返回计数:
select count(A) from my_table
列A
索引信息(如果您需要检查):
type: BTREE
Allows NULL: Yes
Unique: No
Packed: (empty)
你能给我一些解释这个问题吗?我们能做些什么来改善它吗?我不能指望其他列,因为实际上我必须清楚地计算该列,因此返回的计数对每一列都有不同的含义。
解决方案
最快的是COUNT(*)
。这*
是一个约定;它并不意味着“所有列”。 COUNT(1)
是等价的。
COUNT(col)
当您要排除存在的任何col
行时使用NULL
。(这很少需要。)如果col
是声明NOT NULL
的,那么包含确实是一种浪费col
。(注意:我说的是声明的;你说的是不同的:有非空值。)根据Allows NULL: Yes
,你声明了列NULL
,因此COUNT(col)
会检查每一个col
。
会发生什么COUNT(*)
:
- 对于没有 a 的计数
WHERE
,优化器会选择“最小”索引并遍历它。PRIMARY KEY
总是(?)最大的,所以它通常被回避。这个算法的原因是它假设它必须从磁盘读取整个索引;I/O 很慢;而“更小”意味着更少的 I/O。 - 如果有
WHERE
子句,则最佳索引取决于WHERE
子句中的内容——这本身就是一个巨大的话题。
这是一个好主意,NOT NULL
除非您有业务逻辑需要NULLs
(“尚未指定”、“可选”、“已删除”、“不适用”,...)有几种情况(大多数是晦涩难懂的)NOT NULL
表现略好于NULL
.
警告:我的答案适用于 InnoDB,但不完全适用于 MyISAM。
推荐阅读
- reactjs - 如何在 Highcharts React 中重绘使用 SVGRenderer 渲染的文本?
- lua - 使用 busted 测试 Lua 代码时出现零错误
- python - 如何在 Python(Flask) 中模拟一个函数
- ruby-on-rails - 如何在rails中使用form_with和self join?
- android - Android kotlin - Navhost 片段 - 从菜单弹出
- macos - Mac 和 UWP 中 LibVLCSharp VideoView 的自定义渲染器 (Xamarin.Forms)
- javascript - 追加和填充下拉列表多个javascript
- python - 用python(Duffing振荡器)求解非线性非齐次微分方程
- colors - 仅特定页面中的wordpress css背景颜色
- python - 使用烧瓶从 python 调用 julia 返回错误