UNION ALL MYSQL 真的很慢

Posted

技术标签:

【中文标题】UNION ALL MYSQL 真的很慢【英文标题】:UNION ALL MYSQL is really slow 【发布时间】:2020-12-21 20:40:10 【问题描述】:

我在 mysql 中有一个带有 2 个 select from 的查询。当我单独运行这些查询时,它们会在 1 秒内快速运行。但是当我将它们与 union all 结合使用时,网站会冻结,并且在 union all 中执行相同的查询至少需要 20 秒。

知道为什么会这样吗?想不通。

请参阅下面的查询:

SELECT p.user_id, p.description, p.post_id, p.created_at, ps.username AS size_name, ps.username AS user_name, ps.avatar AS avatar, pz.title AS title, pz.slug AS slug 
FROM comments p 
JOIN users ps ON ps.id = p.user_id 
JOIN posts pz ON pz.id = p.post_id 

UNION ALL

SELECT p2.user_id, p2.description, p2.post_id, p2.created_at, ps2.username AS size_name, ps2.username AS user_name, ps2.avatar AS avatar, pz2.title AS title, pz2.slug AS slug 
FROM reply p2 
JOIN users ps2 ON ps2.id = p2.user_id 
JOIN posts pz2 ON pz2.id = p2.post_id 

order by created_at DESC 
LIMIT 10

【问题讨论】:

每个子查询返回多少行? @Barmar 每个大约 2M。 首先在每个 SELECT 中执行 ORDER BY 和 LIMIT 10。然后也对 UNION ALL 结果执行此操作。 您的问题是 ORDER BY 子句。 UNION 需要获取所有记录,然后对它们进行排序。 【参考方案1】:

在与UNION 合并之前,减小每个子查询返回的表的大小。由于只需要前 10 名,因此只需要每个子查询的前 10 名。

SELECT *
FROM (
    (SELECT p.user_id, p.description, p.post_id, p.created_at, ps.username AS size_name, ps.username AS user_name, ps.avatar AS avatar, pz.title AS title, pz.slug AS slug 
    FROM comments p 
    JOIN users ps ON ps.id = p.user_id 
    JOIN posts pz ON pz.id = p.post_id 
    ORDER BY created_at DESC
    LIMIT 10) 
    
    UNION ALL
    
    (
    SELECT p2.user_id, p2.description, p2.post_id, p2.created_at, ps2.username AS size_name, ps2.username AS user_name, ps2.avatar AS avatar, pz2.title AS title, pz2.slug AS slug 
    FROM reply p2 
    JOIN users ps2 ON ps2.id = p2.user_id 
    JOIN posts pz2 ON pz2.id = p2.post_id 
    ORDER BY created_at DESC
    LIMIT 10)
) AS x
order by created_at DESC 
LIMIT 10

【讨论】:

您可以只使用括号而不是子查询来对单个查询进行排序/限制;看我的回答 但是您需要一个外部选择来将其过滤到组合查询的前 10 个。 不,你没有。您可以对单个查询进行排序和限制,也可以对整个联合进行排序和限制 哦,不知道你能做到像你展示的那样。【参考方案2】:

UNION 默认为 UNION DISTINCT。如果您想要 UNION ALL,请明确说明(并且您应该尽可能地这样做,因为 UNION DISTINCT 必须做很多工作才能使它们与众不同)。

另一件事是 order by 和 limit 适用于整个查询。您可能想让每个联合查询也有它们。见https://dev.mysql.com/doc/refman/8.0/en/union.html

联合中的 ORDER BY 和 LIMIT

要将 ORDER BY 或 LIMIT 子句应用于单个 SELECT,请将 SELECT 括起来并将子句放在括号内:

(SELECT a FROM t1 WHERE a=10 AND B=1 ORDER BY a LIMIT 10)
UNION
(SELECT a FROM t2 WHERE a=11 AND B=2 ORDER BY a LIMIT 10);

如果您的快速个人版本确实有这些,那应该会有所帮助。所以是这样的:

(SELECT p.user_id, p.description, p.post_id, p.created_at, ps.username AS size_name, ps.username AS user_name, ps.avatar AS avatar, pz.title AS title, pz.slug AS slug 
FROM comments p 
JOIN users ps ON ps.id = p.user_id 
JOIN posts pz ON pz.id = p.post_id 
order by created_at DESC 
LIMIT 10)

UNION ALL

(SELECT p2.user_id, p2.description, p2.post_id, p2.created_at, ps2.username AS size_name, ps2.username AS user_name, ps2.avatar AS avatar, pz2.title AS title, pz2.slug AS slug 
FROM reply p2 
JOIN users ps2 ON ps2.id = p2.user_id 
JOIN posts pz2 ON pz2.id = p2.post_id 
order by created_at DESC 
LIMIT 10)

order by created_at DESC 
LIMIT 10

【讨论】:

我忘了在 *** 上添加 UNION ALL。我改变了它。谢谢。 该查询将只返回 2 行; 10 和 11。 这将返回最多 20 行。 @Barmar,第一个 SELECT 将返回最多 10 行,所有值 10。第二个 SELECT 将返回最多 10 行,所有值 11。UNION 将删除重复项并只返回一个 10 和一个 11(如果两个值都存在)。 这不代表原始查询,因为他们想要来自两个组合查询的前 10 行。

以上是关于UNION ALL MYSQL 真的很慢的主要内容,如果未能解决你的问题,请参考以下文章

win10电脑打开此电脑资源管理器任务管理器软件等突然很慢很慢,cup内存磁盘利用率却很低

MYSQL:用union查询2个表很慢,如何改进?

SAP migo这个事物代码在做操作的时候,多人操作同一个事务代码时很慢很慢,是啥原因?

jsp做的网页,用tomcat测试时读数据库数据时很慢很慢,是啥原因?

公司网络很慢很卡的原因分析与处理

navicat for mysql 导出数据的坑