2013-07-04 4 views
3

Я знаю, что это распространенный вопрос, и я прочитал несколько других сообщений и статей, но не смог найти тот, который учитывал индексированные поля и объем записей, которые оба запроса могли бы вернуть.Производительность вложенного выбора

Мой вопрос прост на самом деле. Какой из двух рекомендуется здесь, написанный в синтаксисе типа SQL (с точки зрения производительности).

Первый запрос:

Select * 
from someTable s 
where s.someTable_id in 
        (Select someTable_id 
        from otherTable o 
        where o.indexedField = 123) 

Второй запрос:

Select * 
from someTable 
where someTable_id in 
        (Select someTable_id 
        from otherTable o 
        where o.someIndexedField = s.someIndexedField 
        and o.anotherIndexedField = 123) 

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

Теперь второй запрос может запросить суперзадачу базы данных, учитывая, что поле someIndexedField индексировано, но говорят, что у нас есть тысячи или миллионы записей, не будет ли быстрее использовать первый запрос?

Примечание: в базе данных Oracle.

+1

. , В общем, вопрос производительности без указания базы данных не имеет смысла. SQL - это описательный язык, а не процедурный язык, поэтому оптимизатор (часть движка) свободен в выборе любого плана запроса, который лучше всего подходит для данного запроса. –

+0

@GordonLinoff Хорошая точка. База данных - это база данных Oracle. Язык не должен иметь значения, я полагаю, просто написал его в синтаксисе SQL. – mixkat

+1

. , По словам Тома Ките, оптимизатор Oracle достаточно умен, чтобы распознать коррелированные подзапросы и может превратить их в соответствующие объединения (http://asktom.oracle.com/pls/apex/f?p=100:11:0::NO :: P11_QUESTION_ID: 3167884300346662300). У Oracle очень хороший оптимизатор. Что забавно, так это то, что первая версия имеет абсолютно потрясающую производительность в MySQL. , , до версии 5.6, которая исправила проблему. –

ответ

2

О первом запросе:

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

Это не так просто.

В SQL, в основном, НЕ возможно сказать, что будет выполнено первым и что будет выполнено позже.

Потому что SQL - декларативный язык.

Ваши «вложенные выборы» - это только визуально, а не технически.

Пример 1 - в «someTable» у вас есть 10 строк, в «otherTable» - 10000 строк.

В большинстве случаев оптимизатор базы данных сначала прочитает «someTable», а затем проверит другую таблицу, чтобы иметь совпадение. Для этого он может или не может использовать индексы в зависимости от ситуации, мое заполнение в этом случае - оно будет использовать индекс indexedField.

Пример 2 - В «someTable» у вас есть 10000 строк, в «otherTable» - 10 строк.

В большинстве случаев оптимизатор базы данных будет считывать все строки из «otherTable» в памяти, фильтровать их на 123, а затем найти соответствие в индексе someTable PK (someTable_id). В результате - из «otherTable» не будут использоваться индексы.

О втором запросе:

Это полностью отличается от первого. Итак, я не знаю, как их сравнить:

  • Первый запрос связывает две таблицы одной парой: s.someTable_id = o.someTable_id
  • Второй запрос связывает две таблицы двумя парами: s.someTable_id = o.someTable_id И o.someIndexedField = s.someIndexedField.

Обычная практика связывания двух таблиц - это ваш первый запрос. Но o.someTable_id следует проиндексировать.

Так общие правила:

  • все PK - должны индексироваться (они индексируются по умолчанию)
  • все столбцы для фильтрации (как используется в WHERE части) должны быть проиндексированы
  • все столбцы, используемые для обеспечения соответствия между таблицами (включая IN, JOIN и т. д.), также фильтруют, поэтому - должны быть проиндексированы.
  • DB Engine самостоятельно выбирает наилучшие операции заказа (или параллельно). В большинстве случаев вы не можете это определить.
  • Использовать Oracle EXPLAIN PLAN (аналогично существующему для большинства БД) для сравнения планов выполнения различных запросов по реальным данным.
4

В MySQL, если вложенные элементы выбора находятся за одной и той же таблицей, время выполнения запроса может быть адом.

Хороший способ улучшить производительность в MySQL - создать временную таблицу для вложенного выбора и применить основной выбор к этой таблице.

Например:

Select * 
from someTable s1 
where s1.someTable_id in 
        (Select someTable_id 
        from someTable s2 
        where s2.Field = 123); 

Может иметь более высокую производительность:

create temporary table 'temp_table' as (
    Select someTable_id 
    from someTable s2 
    where s2.Field = 123 
); 

Select * 
from someTable s1 
where s1.someTable_id in 
        (Select someTable_id 
        from tempTable s2); 

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