SQLite R * Индекс дерева не используется с DISTINCT - PullRequest
0 голосов
/ 30 мая 2018

В SQLite 3.20.1 у меня есть индекс R * Tree (dog_bounds) и временная таблица (frisbees), созданные следующим образом:

-- Changes infrequently and has ~100k entries
CREATE VIRTUAL TABLE dog_bounds USING rtree (
    dog_id,
    min_x, max_x,
    min_y, max_y
);

-- Changes frequently and has ~100 entries
CREATE TEMPORARY TABLE frisbees (
    frisbee_id,
    min_x, max_x,
    min_y, max_y
);

Запросы выполняются быстро с использованием этого индекса,например так:

EXPLAIN QUERY PLAN
SELECT dog_id FROM dog_bounds AS db, frisbees AS f
    WHERE db.max_x >= f.min_x AND db.max_y >= f.min_y
    AND db.min_x < f.max_x AND db.min_y < f.max_y;

0|0|1|SCAN TABLE frisbees AS f
0|1|0|SCAN TABLE dog_bounds AS db VIRTUAL TABLE INDEX 2:D1D3C0C2

Однако, если я выберу DISTINCT(dog_id), индекс больше не будет использоваться, и запросы станут медленными, даже после ANALYZE:

EXPLAIN QUERY PLAN
SELECT DISTINCT(dog_id) FROM dog_bounds AS db, frisbees AS f
    WHERE db.max_x >= f.min_x AND db.max_y >= f.min_y
    AND db.min_x < f.max_x AND db.min_y < f.max_y;

0|0|0|SCAN TABLE dog_bounds AS db VIRTUAL TABLE INDEX 2:
0|1|1|SCAN TABLE frisbees AS f
0|0|0|USE TEMP B-TREE FOR DISTINCT

Как можноЯ тоже получаю индекс R * Tree?Было бы стыдно дублировать собак!

1 Ответ

0 голосов
/ 30 мая 2018

Оптимизатор запросов считает, что другой порядок выполнения облегчает получение различных dog_id значений.

Перемещение поиска R-дерева в подзапрос, так что оптимизатор запросов вынужден выполнять обе вещи по отдельности.:

SELECT DISTINCT dog_id
FROM (SELECT dog_id
      FROM dog_bounds AS db, frisbees AS f
      WHERE db.max_x >= f.min_x AND db.max_y >= f.min_y
        AND db.min_x <  f.max_x AND db.min_y <  f.max_y);
QUERY PLAN
|--SCAN TABLE dog_bounds AS db VIRTUAL TABLE INDEX 2:
|--SCAN TABLE frisbees AS f
`--USE TEMP B-TREE FOR DISTINCT

Упс, оптимизатор запросов оказался слишком умным и сгладил подзапрос .Но есть способы отключить его (правило 21):

SELECT DISTINCT dog_id
FROM (SELECT dog_id
      FROM dog_bounds AS db, frisbees AS f
      WHERE db.max_x >= f.min_x AND db.max_y >= f.min_y
        AND db.min_x <  f.max_x AND db.min_y <  f.max_y
      LIMIT -1);
QUERY PLAN
|--CO-ROUTINE 0x892A90
|  |--SCAN TABLE frisbees AS f
|  `--SCAN TABLE dog_bounds AS db VIRTUAL TABLE INDEX 2:D1D3C0C2
|--SCAN SUBQUERY 0x892A90
`--USE TEMP B-TREE FOR DISTINCT
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...