它运行哪个列SQL COUNT()有什么区别?

时间:2013-01-17 21:10:09

标签: mysql sql

首先,这不是问In SQL, what's the difference between count(column) and count(*)?

假设我有一个users表,主键为user_id,另一个字段logged_in描述用户是否已立即登录。

运行

之间有区别吗?

SELECT COUNT(user_id) FROM users WHERE logged_in=1

SELECT COUNT(logged_in) FROM users WHERE logged_in=1

查看有多少用户被标记为已登录?也许与索引存在差异?

如果存在特定于数据库的细微差别,我正在运行MySQL。

2 个答案:

答案 0 :(得分:12)

在MySQL中,count函数不会计算空表达式,因此两个查询的结果可能不同。正如评论和Remus的回答中所提到的,这是SQL的一般规则,也是spec的一部分。

例如,请考虑以下数据:

user_id   logged_in
1         1
null      1
此表上的

SELECT COUNT(user_id)将返回1,但SELECT COUNT(logged_in)将返回2.

实际上,只要表格构造正确,问题中示例的结果应始终相同,但使用的索引和查询计划可能会有所不同,即使结果相同。此外,如果这是一个简化的示例,依靠不同的列也可能会改变结果。

另请参阅此问题:MySQL COUNT() and nulls

答案 1 :(得分:5)

对于记录:两个查询返回不同的结果。正如spec所说:

  

返回行中expr的非NULL 值的计数   通过SELECT语句检索。

您可能会争辩说,鉴于logged_in=1的条件,无论如何都会过滤掉NULL logged_in行,并且user_id在表users中不会有NULL。虽然这可能是真的,但它并没有改变查询不同的基本原理。您要求查询优化器在上面进行所有逻辑推理,对于您来说它们可能是显而易见的,但优化器可能不是。

现在,假设两者之间的结果总是相同,答案很简单:不要在生产中运行这样的查询(我的意思是其中之一)。无论你如何切片,都是扫描。 logged_in的基数太低了。保留一个计数器,在每次登录和每次注销事件时更新它。它会随时间漂移,根据需要经常刷新(每天一次,每小时一次)。

至于问题本身:SELECT COUNT(somefield) FROM sometable可以在somefield上使用窄索引,从而减少IO。建议使用*,因为这个空间可供优化器使用它认为合适的任何索引(这会因产品而异,具体取决于我们处理的查询优化器的智能程度用,YMMV)。但是当你开始添加WHERE子句时,可能的替代方法(=要使用的索引)很快就会消失。