具有三个未索引联合表和左连接的 MySQL 查询使数据库负担过重

Posted

技术标签:

【中文标题】具有三个未索引联合表和左连接的 MySQL 查询使数据库负担过重【英文标题】:MySQL Query with three un-indexed unionized tables and a left join overburdens DB 【发布时间】:2016-07-12 10:37:31 【问题描述】:

我有一个相当复杂的 SQL 查询,但我不知道如何让它不那么复杂。如果我尝试运行它,它会使数据库负担过重。如果我稍微简化一下,我可以执行它,但需要很多时间。 我确信有更有效的方法来编写这个查询,但我不知道如何。如果有人能引导我朝着正确的方向前进,我会很高兴!

SELECT master.C_MASTER_ID,
       master.C_MASTER_SUMMARY,
       master.C_MASTER_START,
       master.C_MASTER_END,
       master.C_MASTER_LEVEL,
       master.C_MASTER_SOURCE,
       NULL AS EVT_HAS_Z,
       master.C_MASTER_NOTES,
       master.C_MASTER_SERVICE,
       c2c.CER_CUSTOMER
FROM `C_MASTER` master
LEFT JOIN `c2customer` c2c ON c2c.CER_ID = master.C_MASTER_ID
WHERE 
  master.C_MASTER_END >= NOW()
  AND master.C_MASTER_START >= DATE_SUB(NOW(), INTERVAL 21 DAY)

UNION ALL

SELECT EVT_ID AS C_MASTER_ID,
       EVT_SUMMARY,
       EVT_START_DATE,
       EVT_END_DATE,
       NULL AS C_MASTER_LEVEL,
       NULL AS C_MASTER_SOURCE,
       EVT_HAS_Z,
       NULL AS C_MASTER_NOTES,
       NULL AS C_MASTER_SERVICE,
       NULL AS CER_CUSTOMER
FROM C_event
WHERE EVT_end_date >= NOW()

UNION ALL

SELECT 'WHISPER' AS C_MASTER_CHANGE_ID,
       WISP_SUMMARY,
       WISP_START_DATE,
       WISP_END_DATE,
       NULL AS C_MASTER_LEVEL,
       NULL AS C_MASTER_SOURCE,
       NULL AS EVT_HAS_Z,
       NULL AS C_MASTER_NOTES,
       NULL AS C_MASTER_SERVICE,
       NULL AS CER_CUSTOMER
FROM C_wispering
WHERE WISP_END_DATE >= NOW()

这是我的查询的一个稍微简化的版本,因为否则很难处理寻求帮助的帖子。

【问题讨论】:

您从数据库中获取的行数大约是多少?你的索引是什么样的?在哪些领域等等? @Tikkes 大约 6000 行。我只有 C_MASTER_ID 和 CER_ID 索引。我一直不愿意使用索引,因为我对此一无所知。索引更多字段有什么缺点吗? 在这种情况下,您真的应该考虑阅读索引。 SQL 文档在这方面内容广泛,在处理更复杂的数据库时非常有用。如果使用得当,索引会非常好,并且可以大大提高性能。当然,将索引放在任何事物或所有事物上都有缺点,这就是为什么您应该将索引放在搜索查询中经常需要或经常使用的字段上,组合索引也可以在大多数情况下为您带来优势。 Documentation on indexes @Tikkes 非常感谢你!看来我不能再绕过这个话题了。你会说查询看起来没问题吗? 我相信——当然不知道数据库——但你为什么要这样做:master.C_MASTER_START >= NOW() AND master.C_MASTER_START >= DATE_SUB(NOW(), INTERVAL 21 DAY)?既然您的第二次检查已经表明它应该在过去 21 天之后,那么为什么还要先检查NOW() 【参考方案1】:

您应该单独运行每个查询,以确定导致性能问题的原因。您还可以查看“说明”以查看计划。

顺便说一句,我可以说第一个查询将受益于 c_master(C_MASTER_START, C_MASTER_ID)c2customer(CER_ID, CER_CUSTOMER) 上的索引。

第二个将受益于C_event(EVT_end_date) 上的索引。第三个:C_wispering(WISP_END_DATE)

【讨论】:

对此的旁注,当在日期时间上放置索引时,考虑不包括毫秒/秒/分钟并以小时为目标以减少负载可能是明智的。有关性能的更多信息也可以在this *** question 上找到 非常感谢您的回答!!到目前为止,我只有 CER_ID 和 C_MASTER_ID 索引。我一直不愿意使用索引,只是因为我对此了解不多:/ - 索引更多字段是否有任何缺点,索引您建议的字段时是否有任何风险,或者我可以索引吗? (我在数据库上确实有一个每日写入过程,到目前为止,当我索引 C_MASTER_ID 和 CER_ID 时,它还没有被触及,但我担心如果我再索引它会减慢很多) @tikkes 恕我直言,DATETIME 索引无疑是处理此类事情的最佳方式。您提供的链接中接受的答案包含一些关于日期时间索引复杂性的严重错误信息。 @OllieJones 你知道如果我索引日期时间是否存在显着减慢日常写入操作的风险吗? 如果您有 6 个 gigarows,可能会有,但可能没有。用 6megarows,当然不是。使用 6000 行,您甚至不会注意到它。 mysql 和其他 RDMS 系统是为处理非常大的卷而构建的。

以上是关于具有三个未索引联合表和左连接的 MySQL 查询使数据库负担过重的主要内容,如果未能解决你的问题,请参考以下文章

为啥对三个表的联合 mysql 查询比在不可能的 where 子句上连接更快?

LINQ to SQL 执行联合和左外连接

如何使用 group_concat 和左连接计算 mysql 查询的结果

mysql 联合模糊查询问题?

MySql内连接查询

CI MySQL查询连接表和where语句不返回所有行