2009-03-19 2 views
4

Я использую реализацию JPA Hibernate с MySQL 5.0.67. MySQL настроен на использование InnoDB.Предложение SQL IN медленнее, чем отдельные запросы

Выполнение запроса JPA (который переведен на SQL), я обнаружил, что использование предложения IN происходит медленнее, чем выполнение отдельных запросов. Пример:

SELECT p FROM Person p WHERE p.name IN ('Joe', 'Jane', 'Bob', 'Alice') 

медленнее, чем четыре отдельных запросов:

SELECT p FROM Person p WHERE p.name = 'Joe' 
SELECT p FROM Person p WHERE p.name = 'Jane' 
SELECT p FROM Person p WHERE p.name = 'Bob' 
SELECT p FROM Person p WHERE p.name = 'Alice' 

Почему это? Это ограничение производительности MySQL?

ответ

11

Это известный недостаток в MySQL.

Часто верно, что использование UNION выполняется лучше, чем запрос диапазона, как тот, который вы показываете. MySQL не использует индексы очень разумно для выражений с использованием IN (...). Аналогичная дыра существует в оптимизаторе для булевых выражений с OR.

См. http://www.mysqlperformanceblog.com/2006/08/10/using-union-to-implement-loose-index-scan-to-mysql/ для получения некоторых пояснений и подробных контрольных показателей.

Оптимизатор постоянно совершенствуется. Недостаток одной версии MySQL может быть улучшен в последующей версии. Поэтому стоит проверить ваши запросы на разные версии.

Также полезно использовать UNION ALL вместо UNION. Оба запроса используют временную таблицу для хранения результатов, но разница заключается в том, что UNION применяет DISTINCT к результирующему набору, что требует дополнительной неиндексированной сортировки.

+0

Имеет ли SQL Server этот недостаток? –

+0

Я не пользователь SQL Server, поэтому я не знаю ответа. Лучше всего попробовать обе формы запросов в Query Analyzer и использовать параметр меню «Показать вариант выполнения». –

+0

Нет, SQL Server не имеет этой проблемы –

1

Если вы используете оператор IN, это не сильно отличается, чем сказать:

(p.name = 'Joe' OR p.name = 'Jane' OR p.name = 'Bob' OR p.name = 'Alice') 

Эти четыре условия, которые должны быть проверены на каждой строке, что запрос должен учитывать. Конечно, каждый другой запрос, который вы цитируете, имеет только одно условие. Я не верю в большинство сценариев реального мира, которые выполняют четыре таких запроса быстрее, так как вам нужно учитывать время, необходимое вашему клиенту для чтения наборов результатов и что-то делать с ними. В этом случае IN выглядит довольно красиво; даже лучше, если он может использовать индекс.

0

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

Это поможет получить индекс в столбце имен.

+0

Я измеряю полное истекшее время. –

1

Запрос, столь же простой, как продемонстрированный IN, не должен иметь проблемы с оптимизатором, предпочитающим использовать индекс. Работа UNION, упомянутая Биллом, требуется только иногда, когда у вас есть более сложные запросы. Это может быть проблемой статистики индекса.

Вы сделали ANALYZE на рассматриваемом столе?

Сколько строк в таблице и сколько соответствует предложению IN?

Что говорит EXPLAIN для запросов, о которых идет речь?

0

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

Следующая методика используется практически для каждого приложения PHP/MySQL, которое я создаю.

я использовать предложение совсем немного с числовыми ключами:

например

захватить пять мастер-элементы и все subites могут быть:

$master_arr = mysql_query(
select * from master table where master_id in (1,7,9,10) 
); 

затем:

$subitem_arr = mysql_query(
    select * from subitems table where par_master_id in (1,7,9,10) 
); 

оных Подмассив к основным пунктам:

foreach($subitem_arr AS $sv){ 
    $m_key = $sv['par_master_id']; 
    $s_key = $sv['subitem_id']; 
    $master_arr[$m_key]['subitem'][$s_key] = $sv; 
} 

Это делает две вещи : 1.) Таблицы не все удерживаются одновременно с соединением 2.) только два MySQL запросы производят дерево данных

0

вы можете сделать в пункте быстрее, если вы получаете значения первым затем вставлять значения в в пункте вместо внедрения запроса SQL в инструкцию SQL

здесь example of using in clause

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