我有一个涉及几行时差小于2小时(〜0.08333天)的查询:
SELECT mt1.*, mt2.* FROM mytable mt1, mytable mt2 WHERE ABS(JULIANDAY(mt1.date) - JULIANDAY(mt2.date)) < 0.08333
该查询相当慢,即〜1秒(该表具有〜10k行)。
一个主意是使用INDEX。显然CREATE INDEX id1 ON mytable(date)没有任何改善,这是正常的。
INDEX
CREATE INDEX id1 ON mytable(date)
然后我注意到了神奇的查询 CREATE INDEX id2 ON mytable(JULIANDAY(date))
CREATE INDEX id2 ON mytable(JULIANDAY(date))
使用时没有帮助:
... WHERE ABS(JULIANDAY(mt1.date) - JULIANDAY(mt2.date)) < 0.08333
... WHERE JULIANDAY(mt2.date) - 0.08333 < JULIANDAY(mt1.date) < JULIANDAY(mt2.date) + 0.08333
…但是在使用时大大提高了性能(查询时间愉快地除以50!):
... WHERE JULIANDAY(mt1.date) < JULIANDAY(mt2.date) + 0.08333 AND JULIANDAY(mt1.date) > JULIANDAY(mt2.date) - 0.08333
当然1.,2和3.在数学上是等效的,
|x-y| < 0.08333 <=> y - 0.08333 < x < y + 0.08333 <=> x < y + 0.08333 AND x > y - 0.08333
问题:为什么解决方案1.和2.不使用INDEX,而解决方案3.在使用它呢?
笔记:
我正在使用Python + Sqlitesqlite3模块
sqlite3
在执行EXPLAIN QUERY PLAN SELECT ...以下操作时,确认事实解决方案1.和2.未使用索引:
EXPLAIN QUERY PLAN SELECT ...
(0, 0, 0, u'SCAN TABLE mytable AS mt1')
(0, 1, 1, u’SCAN TABLE mytable AS mt2’)
执行时显示事实解决方案3.正在使用索引EXPLAIN QUERY PLAN SELECT ...:
(0, 0, 1, u'SCAN TABLE mytable AS mt2') (0, 1, 0, u'SEARCH TABLE mytable AS mt1 USING INDEX id2 (<expr>>? AND <expr><?)')
我认为,根据的包含 AND 是:
AND
查询中的WHERE子句分为“条款”,其中每个条款都由AND运算符分隔。如果WHERE子句由由OR运算符分隔的约束组成,则整个子句将被视为应用OR子句优化的单个“项”。
SQLite查询优化器概述
也许值得一试ANALYZE,看看是否可以改善情况。
ANALYZE
根据评论:
我认为前面添加的段落可以阐明为什么ABS(xy)<k不使用索引,为什么x expression …
添加了以下内容。
要通过索引使用,术语必须具有以下形式之一: 列=表达式 列IS表达式 列>表达式 列> =表达式 列<表达式 列<=表达式 表达式=列 表达式>列 表达式> =列 表达式<列 表达式<=列 列IN(表达式列表) 列IN(子查询) 列IS NULL
我不确定是否可以使用BETWEEN(例如WHERE column BETWEEN expr1 AND expr2)。
BETWEEN
WHERE column BETWEEN expr1 AND expr2