小编典典

SQL INDEX不用于WHERE ABS(xy)<k条件,但用于y-k <x <y + k条件

sql

我有一个涉及几行时差小于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)没有任何改善,这是正常的。


然后我注意到了神奇的查询 CREATE INDEX id2 ON mytable(JULIANDAY(date))

  1. 使用时没有帮助:

    ... WHERE ABS(JULIANDAY(mt1.date) - JULIANDAY(mt2.date)) < 0.08333
    
  2. 使用时没有帮助:

    ... WHERE JULIANDAY(mt2.date) - 0.08333 < JULIANDAY(mt1.date) < JULIANDAY(mt2.date) + 0.08333
    
  3. …但是在使用时大大提高了性能(查询时间愉快地除以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模块

  • 在执行EXPLAIN QUERY PLAN SELECT ...以下操作时,确认事实解决方案1.和2.未使用索引:

    (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><?)')

阅读 194

收藏
2021-04-07

共1个答案

小编典典

我认为,根据的包含 AND 是:

查询中的WHERE子句分为“条款”,其中每个条款都由AND运算符分隔。如果WHERE子句由由OR运算符分隔的约束组成,则整个子句将被视为应用OR子句优化的单个“项”。

SQLite查询优化器概述

也许值得一试ANALYZE,看看是否可以改善情况。

根据评论:

我认为前面添加的段落可以阐明为什么ABS(xy)<k不使用索引,为什么x expression …

添加了以下内容。

要通过索引使用,术语必须具有以下形式之一:
列=表达式
列IS表达式
列>表达式
列> =表达式
列<表达式
列<=表达式
表达式=列
表达式>列
表达式> =列
表达式<列
表达式<=列
列IN(表达式列表)
列IN(子查询)
列IS NULL

我不确定是否可以使用BETWEEN(例如WHERE column BETWEEN expr1 AND expr2)。

2021-04-07