如何使用嵌套的SELECT子查询优化UPDATE?

时间:2019-01-16 00:47:09

标签: mysql sql join optimization subquery

我写了一个复杂的UPDATE查询,它可以工作,但是看起来很危险。这是我想要做的:

在每个主题用户“ Bob123”中,匿名发布。在主题中匿名发布时,您将获得该主题的唯一匿名索引。

说我想将两个主题合并在一起。 Bob123在两个主题中都有不同的anon索引,因此他唯一的anon索引不会唯一。我只有两段数据可以使用:$ topic_id(您要合并到的主题ID)和$ post_id_list(所有要合并的帖子ID)。

我想更新该主题中每个poster_id的帖子的所有anonymous_index条目。该匿名索引必须是他们在另一个主题合并到该主题之前在该主题中拥有的原始索引。

第一个SELECT查询首先选择已移动帖子的匿名索引。 外部SELECT查询获取主题中那些合并的发布者的第一个非合并帖子的匿名索引(如果为> 0),并从第一个查询中选择一个合并的匿名索引。

然后,我对其进行更新。只要该主题中那些发帖人的匿名索引与旧索引不相等,我都会对其进行更新。

这里缺少一些简单的东西吗?我不喜欢在子查询中有一个子查询的事实。

起初,我使用HAVING MIN(anonymous_index) <> MAX(anonymous_index)AND post_id NOT IN ($merged_post_list)来选择需要更新的发帖人ID列表和未合并的匿名索引,但是它返回了0行。如果合并的帖子在所有原始帖子之前(且具有较大的anon索引),则最小的anon索引将与该海报的最大索引匹配。因此,使另一个子查询解决此问题...

$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 :(得分:0)

考虑对三个自联接进行内部联接更新:

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