我有 3 张桌子:
users
movements
unique_ids
我想获取从 3 月到现在的用户在 3 月注册的记录,计算他们动作的唯一 id,并在最后计算它的总数:
SELECT MONTH(mo.ctime) AS month, COUNT(DISTINCT(unique_id))
FROM users us, movements mo,unique_ids id
WHERE us.time_field > '2014-03-01' AND us.time_field < '2014-03-31 23:59:59'
AND mo.time_field > '2014-03-01'
AND us.room_name LIKE 'name'
AND us.room_name=mo.room_name AND us.user=mo.user AND id.id_log=mo.id_log
GROUP BY month WITH ROLLUP
问题是几个月前在其他查询中,我意识到将DATE()添加到 time_field 到 WHERE 子句中可以加快查询速度,但是将其添加到显示的查询中,得到的结果与最初的结果不同。
time_field > 'x' AND DATE(time_field) > 'x' inside WHERE 子句有什么区别?
只是解决这个问题
不同之处在于查询优化器如何处理它们。
WHERE
子句有time_field > 'x'
,这会向查询优化器发出信号以尝试查找任何索引,以便利用它进行范围扫描。WHERE
子句有DATE(time_field) > 'x'
,则这会向查询优化器发出信号,将所有索引置于总线之下,因为必须在整个表(以全表扫描的形式)或连接结果中调用DATE 函数。根据 的键分布
time_field
,DATE(time_field) > 'x'
如果值占索引的很大比例,则触发全表扫描恰好比对索引的范围扫描更好。使用 InnoDB 更是如此,因为全表扫描会通过聚集索引(其中PRIMARY KEY
和行数据共存),而打开二级索引time_field
会导致除了聚集索引之外还要查找二级索引。如果这样的二级索引具有不平衡的键分布,那么无论如何都会忽略这样的索引而支持全表扫描。此猜想仅表明您当前的数据集。其他人的数据集可能具有更好(均匀分布、更平衡)的密钥分布,从而
time_field > 'x'
比DATE(time_field) > 'x'
.要查看此类差异,请
EXPLAIN
在两个SELECT
查询上运行。结果可能不同。