首先,这不是问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。
答案 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子句时,可能的替代方法(=要使用的索引)很快就会消失。