Как преобразовать оператор выбора MySQL с подзапросом в ту же таблицу в оператор обновления? - PullRequest
0 голосов
/ 09 ноября 2018

У меня есть следующий рабочий оператор выбора.

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. Таким образом, после оптимизации времени выполнения я получил приведенный выше оператор выбора.

Существует также ловушка с исходной таблицей, которая должна быть обновлена. option_value - это фактическое поле, которое также существует в исходной таблице (но со значением NULL).

Проблемы, с которыми я столкнулся при попытке преобразовать оптимизированный оператор выбора выше в оператор обновления, заключались в основном в том, что я не могу получить доступ к t1.id из подзапроса.

Как преобразовать оператор выбора в оператор обновления, не теряя при этом оптимизации производительности?

Ответы [ 3 ]

0 голосов
/ 09 ноября 2018

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

UPDATE tblfoo f
INNER JOIN
(
    SELECT DISTINCT refid, content
    FROM tblbar
) b
    ON f.id = b.refid
SET f.option_value = b.content;
0 голосов
/ 09 ноября 2018

Если вы обновляете все строки, то наиболее эффективным методом может быть:

UPDATE tblfoo f
    SET f.option_value = (SELECT b.content FROM tblbar WHERE f.id = b.refid LIMIT 1);

В частности, это может использовать индекс tblbar(refid, content).

0 голосов
/ 09 ноября 2018

Ваш коррелированный подзапрос может быть дополнительно оптимизирован, избегая 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;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...