我尝试创建一个SQL查询,在特定时间范围内获得服务的总出勤率。
我的查询工作正常,但出于某种原因,它在单个表上进行全表扫描而不使用索引(即使我使用FORCE INDEX
时)。
这是my schema, query and output的实时样本。
运行查询后,您会看到st
具有service_id
的可能密钥,而是执行全表扫描(ALL
)。
我一直在不同的表连接上使用FORCE INDEX
,但似乎无法使所有连接的表使用正确的索引。更改一个索引会影响另一个索引我认为我要么设置错误的索引,要么完全错过了一些明显的东西。
有什么想法吗?
答案 0 :(得分:3)
一个想法。我不认为你的查询正在做你认为它正在做的事情。
在我看来,你已经有了不应该有的parens。 这里:
WHERE st.time BETWEEN('2016-01-01' AND '2016-01-03') AND
st.deleted = 0
我认为MySQL正在评估其中的内容......
('2016-01-01' AND '2016-01-03')
并且计算结果为TRUE,返回为整数值1
。所以你拥有的东西实际上相当于:
WHERE st.time BETWEEN 1 AND st.deleted = 0
有一个优先顺序......要么首先评估相等比较,要么AND
(被认为是BETWEEN
比较的一部分)。它将等同于:
WHERE ( st.time BETWEEN 1 AND st.deleted ) = 0
-OR -
WHERE st.time BETWEEN 1 AND ( st.deleted = 0 )
我需要运行一些测试来弄清楚它在做什么。但在任何一种情况下,它不可能是你期望的,或者你真正想要的。 MySQL无法使用带有time
前导列的索引进行范围扫描,因为在此之前它需要deleted
列的值。
我建议您在开始使用索引之前先修复查询。
我在想你想要的是这样的:
WHERE st.time BETWEEN '2016-01-01' AND '2016-01-03'
AND st.deleted = 0
为了比较,请考虑这些陈述的回报:
SELECT '2016-01-02' BETWEEN ('2016-01-01' AND '2016-01-03') AND 1=1 --> 0
SELECT '2016-01-02' BETWEEN '2016-01-01' AND '2016-01-03' AND 1=1 --> 1
SELECT '2016-01-02' BETWEEN ('2016-01-01' AND '2016-01-03') --> syntax error