2013-07-15 2 views
3

Я читал, что соединения лучше, чем подзапросы.Как понять результат SQLite `EXPLAIN QUERY PLAN`?

Но

EXPLAIN QUERY PLAN 
SELECT Queue.Id, NULL 
    FROM Queue 
    INNER JOIN LastQueue 
    ON Queue.Id=LastQueue.Id 

дает

Array 
(
    [0] => Array 
     (
      [selectid] => 0 
      [order] => 0 
      [from] => 0 
      [detail] => SCAN TABLE Queue (~1000000 rows) 
     ) 

    [1] => Array 
     (
      [selectid] => 0 
      [order] => 1 
      [from] => 1 
      [detail] => SEARCH TABLE LastQueue USING INTEGER PRIMARY KEY (rowid=?) (~1 rows) 
     ) 

) 

в то время как

EXPLAIN QUERY PLAN 
SELECT Queue.Id, NULL 
    FROM Queue 
    WHERE (SELECT 1 FROM LastQueue WHERE Queue.Id=LastQueue.Id) IS NOT NULL 

дает

Array 
(
    [0] => Array 
     (
      [selectid] => 0 
      [order] => 0 
      [from] => 0 
      [detail] => SCAN TABLE Queue (~500000 rows) 
     ) 

    [1] => Array 
     (
      [selectid] => 0 
      [order] => 0 
      [from] => 0 
      [detail] => EXECUTE CORRELATED SCALAR SUBQUERY 1 
     ) 

    [2] => Array 
     (
      [selectid] => 1 
      [order] => 0 
      [from] => 0 
      [detail] => SEARCH TABLE LastQueue USING INTEGER PRIMARY KEY (rowid=?) (~1 rows) 
     ) 

) 

Думаю, мне нужно умножить количество строк, чтобы получить представление о стоимости. Я не ошибаюсь?

Затем

  • Использование присоединиться: 1000000 * 1
  • Использование подзапроса: 500000 * 1 * 1

Тогда, это подзапрос быстрее, чем присоединиться?

Есть ли хороший учебник, чтобы узнать, как понимать результаты EXPLAIN/EXPLAIN QUERY PLAN?

И почему он говорит, что очередь SCAN TABLE ~ 1000000 и ~ 500000, когда эта таблица имеет 76 строк?

+1

Вот ссылка (** https: //www.sqlite.org /eqp.html**) к официальному документу для ** Объяснить план запроса **. Он объясняет все, что вам нужно знать, чтобы использовать План объяснений –

ответ

6

Линия EXECUTE CORRELATED SCALAR SUBQUERY 1 только там, потому что вы используете другой синтаксис запроса.

Фактическое выполнение в обоих случаях одинаково: SQLite просматривает все записи таблицы Queue и пытается найти соответствующую запись в таблице LastQueue.

То, что оценки запись отсчеты различны не представляет интереса для вас, потому что вы знаете, что фактического количества записей таким же.

Соединения могут быть лучше, чем подзапросы в других базах данных, но в SQLite, который использует только вложенные объединения циклов, единственное отличие состоит в том, что объединение позволяет SQLite выбирать внешнюю и внутреннюю таблицу в соединении.

В любом случае, вы должны написать запрос самым простым и удобным для пользователя способом и оптимизировать его, только если вы измерили, что получаете заметное и необходимое улучшение.


Пожалуйста, обратите внимание, что вместо того, чтобы:

WHERE (SELECT ...) IS NOT NULL 

было бы более идиоматических написать:

WHERE EXISTS (SELECT ...) 
1

объяснение даёт неповторимые подсчеты для ваших таблиц. Попробуйте использовать анализ, чтобы собирать статистику по таблицам, а затем повторите попытку.

Я думаю, вы найдете, что оба запроса вернутся с почти той же скоростью. Возможно, подзапрос медленнее из-за дополнительного шага. Здесь важно отметить «SCAN TABLE», что означает, что он смотрит на все строки на диске.

http://www.sqlite.org/lang_analyze.html

Также возможно нет индексов на вашем столе? Потому что он должен их использовать, но, похоже, это не так. Убедитесь, что вы используете первичный ключ в инструкции create table.

http://www.sqlite.org/lang_createtable.html

+0

После анализа объединение составляет 76 * 1, а подзапрос - 38 * 1 * 1 строки , И да, у меня есть первичный ключ ('CREATE TABLE 'Queue' ('Id' INTEGER PRIMARY KEY NOT NULL)'). Но я правильно умножаю число строк, или я должен делать другие операции для расчета стоимости? – Oriol

+0

Почему, по вашему мнению, SQLite может использовать другой индекс? Для соединения он должен * видеть все записи «Queue». –

+0

@CL. не один индекс, только 1 индекс (т.е. PK) и таблица LastQueue, потому что это внутреннее соединение. – beiller

Смежные вопросы