MySQL Update Query Optimization - подзапросы или нет? - PullRequest
4 голосов
/ 16 декабря 2010

Какой запрос будет самым быстрым: мои собственные тесты не показывают очевидных результатов:

Query1:

UPDATE items, brands SET items.brand_id = brands.id WHERE brands.name = 'apple'

- против -

Query2:

UPDATE items SET brand_id = (SELECT id FROM brands WHERE name = 'apple')

Я не могу найти никаких данных об этом в Google; может быть, некоторые эксперты по SQL знают ответ?

Глядя только на синтаксис, я лично предпочитаю первый. В то время как другие, кого я говорю, предпочитают второе (для большей очевидности)?

Ответы [ 2 ]

5 голосов
/ 16 декабря 2010

Я ожидал бы, что они будут работать одинаково быстро, но при выполнении тестов для ~ 4M записей в таблице innoDB отображаются следующие результаты:

mysql> update t, (select now() value) onerow set update_date = onerow.value;
Query OK, 3999960 rows affected (2 min 12.32 sec)
Rows matched: 3999960  Changed: 3999960  Warnings: 0

mysql> update t set update_date = (select now());
Query OK, 3999960 rows affected (1 min 28.66 sec)
Rows matched: 3999960  Changed: 3999960  Warnings: 0

(при повторном запуске теста через 2 мин 11,52 сек и 1 мин26,67 с соответственно)

Причины могут заключаться в том, что mysql обрабатывает обновления одной таблицы и обновления нескольких таблиц, см. Документы .

Примечание.о том, как mysql обрабатывает UPDATE - он имеет некоторые ужасные отклонения от стандарта SQL (он чувствителен к порядку присваивания, который даже не согласуется между обновлением одной таблицы и обновлением нескольких таблиц - при этом обновление нескольких таблиц в основном не является детерминированным в выражениях, таких каккак UPDATE t SET column1=column1+100, column2=column1)

0 голосов
/ 16 декабря 2010

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

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

Ни то, ни другое не особенно хорошо ... только вопрос, который хуже.:)

Вы хотите обновить всю таблицу items?

Вы пытались найти @ 1012 * s эквивалентных SELECT s двух запросов?

EXPLAIN
SELECT items.brand_id, brands.id 
FROM items, brands 
WHERE brands.name = 'apple'

и

EXPLAIN 
SELECT brand_id, id
FROM items, (SELECT id FROM brands WHERE name = 'apple') a

Еще лучше, запустите UPDATE с / эквивалентные SELECTS с и выполните несколько SHOW STATUS LIKE 'handler_%', чтобы точно узнать, сколько строк читается /написано.

...