У меня есть следующее рабочее предложение выбора.
SELECT t1.id, t1.option_key, (
SELECT
t3.content AS option_value
FROM tblfoo t2
LEFT OUTER JOIN tblbar t3 ON( t3.refid = t2.id )
WHERE t2.id = t1.id
LIMIT 1
) AS option_value
FROM tblfoo t1
Структура таблицы выглядит следующим образом:
| tblfoo |
+----+------------+--------------+
| id | option_key | option_value |
+----+------------+--------------+
| 1 | foo | NULL |
| 2 | bar | NULL |
| 3 | baz | NULL |
| tblbar |
+----+-----------------+
| id | refid | content |
+----+-----------------+
| 1 | 1 | value1 |
| 1 | 2 | value2 |
| 1 | 3 | value3 |
Результат оператора update должен быть таким:
| tblfoo |
+----+------------+--------------+
| id | option_key | option_value |
+----+------------+--------------+
| 1 | foo | value1 |
| 2 | bar | value2 |
| 3 | baz | value3 |
Я хочу обновить option_value
с помощью tblfoo
используя связанные данные из content
из tblbar
. К сожалению, tblbar
может иметь несколько записей для refid
с одинаковым значением. Вот почему существует необходимость в LIMIT 1
(или GROUP BY t,id
или DISTINCT
) с подзапросом.
Я выяснил, что запрос значительно быстрее, когда я делаю подзапрос с LIMIT 1
вместо подзапроса с SELECT DISTINCT
или объединение в сочетании с GROUP BY t1.id
Так что после оптимизации времени выполнения я закончил с утверждением select выше.
Есть также улов с исходной таблицей, которая должна быть обновлена. option_value
- фактическое поле, которое также существует в исходной таблице (но со значением NULL
).
Проблемы, с которыми я столкнулся при попытке преобразовать оптимизированный оператор выбора выше в оператор обновления, были главным образом в том, что я не могу получить доступ к t1.id
из подзапроса.
Как преобразовать оператор выбора в оператор обновления, не теряя при этом оптимизации производительности?
Просто используйте объединение обновлений с подзапросом, который находит различные значения в tblbar
:
UPDATE tblfoo f
INNER JOIN
(
SELECT DISTINCT refid, content
FROM tblbar
) b
ON f.id = b.refid
SET f.option_value = b.content;
SET f.content = b.option_value;
, Можете ли вы обновить свой ответ? Тогда я могу принять это :)
Ваш коррелированный подзапрос может быть дополнительно оптимизирован, избегая Left Join
между двумя таблицами. Вместо этого вы можете напрямую получить значение content
из второй таблицы.
Для обновления вы можете использовать ваш запрос select
в качестве производной таблицы и присоединить его к исходной таблице:
UPDATE tblfoo AS tfoo
JOIN (
SELECT t1.id,
(SELECT t3.content AS option_value
FROM tblbar t3
WHERE t3.refid = t1.id
LIMIT 1
) AS option_value
FROM tblfoo t1
) AS dt ON dt.id = tfoo.id
SET tfoo.option_value = dt.option_value;
Если вы обновляете все строки, то наиболее эффективным методом может быть:
UPDATE tblfoo f
SET f.option_value = (SELECT b.content FROM tblbar WHERE f.id = b.refid LIMIT 1);
В частности, это может использовать индекс tblbar(refid, content)
.