Как оптимизировать UPDATE с вложенным подзапросом SELECT? - PullRequest
0 голосов
/ 16 января 2019

Я написал сложный запрос UPDATE, и он работает, но выглядит угрожающе. Вот что я пытаюсь сделать:

В каждой теме пользователь 'Bob123' разместил анонимно. Когда вы публикуете анонимно в теме, вы получаете уникальный анонимный индекс для этой темы.

Скажем, я хочу объединить две темы. У Bob123 разные индексы анонов в обеих темах, поэтому его уникальный индекс анонов не будет уникальным. У меня есть только две части данных для работы: $ topic_id, идентификатор темы, с которой вы объединяетесь, и $ post_id_list, все идентификаторы сообщений, которые были объединены.

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

Первый запрос SELECT сначала выбирает анон-индексы перемещенных сообщений. Внешний запрос SELECT получает анон-индекс первого не объединенного поста (если он равен > 0) из этих объединенных постеров в теме и выбирает индекс анонного слияния из первого запроса.

Затем я обновляю его. Везде, где анонный индекс этих постеров в этой теме не равен старому индексу, я обновляю его.

Есть что-то простое, что я здесь упускаю? Мне не нравится тот факт, что у меня есть подзапрос в подзапросе.

Сначала я использовал HAVING MIN(anonymous_index) <> MAX(anonymous_index) вместе с AND post_id NOT IN ($merged_post_list), чтобы выбрать список идентификаторов плаката, который необходимо обновить, и индекс unonged anon, но он вернул 0 строк с этим. Если объединенная публикация ДО всех оригинальных публикаций (и имеет больший индекс анона), то минимальный индекс анона будет соответствовать максимальному индексу для этого постера. Поэтому создание другого подзапроса исправило это ...

$merged_post_list = implode(',', $post_id_list);

...

UPDATE " . POSTS_TABLE . " AS p
INNER JOIN (    SELECT p.post_id, p.anonymous_index AS old_index,
                       merged.poster_id, merged.anonymous_index AS new_index
                FROM " . POSTS_TABLE . " AS p,
                (       SELECT poster_id, anonymous_index
                        FROM " . POSTS_TABLE . "
                        WHERE post_id IN ($merged_post_list)
                        AND topic_id = $topic_id
                        AND anonymous_index > 0
                ) AS merged
                WHERE p.post_id NOT IN ($merged_post_list)
                AND p.topic_id = $topic_id
                AND p.anonymous_index > 0
                AND p.poster_id = merged.poster_id
                GROUP BY merged.poster_id
) AS postdata
SET p.anonymous_index = postdata.old_index
WHERE p.topic_id = $topic_id
AND anonymous_index > 0
AND anonymous_index <> postdata.old_index
AND p.poster_id = postdata.poster_id

post_id - основной индекс, poster_id и topic_id - также индексы.

Вот пример поведения:

До слияния:

|post_id_____poster_id_____anonymous_index|
| 11         | 3           | 2            |
| 12         | 22          | 1            |
| 14         | 22          | 1            |
| 15         | 3           | 2            |

После слияния:

|post_id_____poster_id_____anonymous_index|
| 10         | 22          | 4            |
| 11         | 3           | 2            |
| 12         | 22          | 1            |
| 13         | 3           | 4            |
| 14         | 22          | 1            |
| 15         | 3           | 2            |
| 16         | 22          | 4            |

После ОБНОВЛЕНИЯ (вышеуказанный запрос):

|post_id_____poster_id_____anonymous_index|
| 10         | 22          | 1            |
| 11         | 3           | 2            |
| 12         | 22          | 1            |
| 13         | 3           | 2            |
| 14         | 22          | 1            |
| 15         | 3           | 2            |
| 16         | 22          | 1            |

РЕДАКТИРОВАТЬ: я сделал следующий индекс и альтернативный запрос SELECT, чтобы избежать двух подзапросов, как эти тарифы ?: (topic_id, poster_id, anonymous_index, post_id)

SELECT p.post_id, p.anonymous_index AS old_index,
        merged.poster_id, merged.anonymous_index AS new_index
FROM " . POSTS_TABLE . " AS p,
     " . POSTS_TABLE . " AS merged
WHERE p.topic_id = $topic_id
AND p.anonymous_index > 0
AND p.post_id NOT IN ($post_list)
AND p.poster_id = merged.poster_id
AND merged.topic_id = $topic_id
AND merged.anonymous_index > 0
AND merged.post_id IN ($post_list)
GROUP BY merged.poster_id
ORDER BY NULL

1 Ответ

0 голосов
/ 16 января 2019

Рассмотрим обновление внутреннего объединения через три самостоятельных объединения:

UPDATE " . POSTS_TABLE . " AS final
INNER JOIN " . POSTS_TABLE . " AS p
  ON p.poster_id = final.poster_id
  AND p.topic_id = final.topic_id
  AND p.topic_id = $topic_id
  AND p.post_id NOT IN ($merged_post_list)
  AND p.anonymous_index > 0
INNER JOIN " . POSTS_TABLE . " AS merged 
  ON merged.poster_id = p.poster_id
  AND merged.topic_id = p.topic_id 
  AND merged.topic_id = $topic_id
  AND merged.post_id IN ($merged_post_list)
  AND merged.anonymous_index > 0

SET final.anonymous_index = p.anonymous_index

WHERE final.anonymous_index > 0
  AND final.anonymous_index <> p.anonymous_index
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...