【问题标题】:Temp tables vs subqueries in inner join内部连接中的临时表与子查询
【发布时间】:2018-06-20 14:52:18
【问题描述】:

两个 SQL,返回相同的结果。我的第一个连接在子查询上,第二个最后的查询是一个连接,与我之前创建/填充它们的临时连接

SELECT COUNT(*) totalCollegiates, SUM(getFee(c.collegiate_id, dateS)) totalMoney
FROM collegiates c
LEFT JOIN (
    SELECT collegiate_id FROM collegiateRemittances r
    INNER JOIN remittances r1 USING(remittance_id)
    WHERE r1.type_id = 1 AND r1.name = remesa   
) hasRemittance ON hasRemittance.collegiate_id = c.collegiate_id
WHERE hasRemittance.collegiate_id IS NULL AND c.typePayment = 1 AND c.active = 1 AND c.exentFee = 0 AND c.approvedBoard = 1 AND IF(notCollegiate, c.collegiate_id NOT IN (notCollegiate), '1=1');



DROP TEMPORARY TABLE IF EXISTS hasRemittance;

CREATE TEMPORARY TABLE hasRemittance
    SELECT collegiate_id FROM collegiateRemittances r
    INNER JOIN remittances r1 USING(remittance_id)
    WHERE r1.type_id = 1 AND r1.name = remesa;

SELECT COUNT(*) totalCollegiates, SUM(getFee(c.collegiate_id, dateS)) totalMoney
FROM collegiates c
LEFT JOIN hasRemittance ON hasRemittance.collegiate_id = c.collegiate_id
WHERE hasRemittance.collegiate_id IS NULL AND c.typePayment = 1 AND c.active = 1 AND c.exentFee = 0 AND c.approvedBoard = 1 AND IF(notCollegiate, c.collegiate_id NOT IN (notCollegiate), '1=1');

对于几千条记录,哪个性能更好?

【问题讨论】:

  • 在两个查询上运行 EXPLAIN。即使有人在这里回答,我想你也会学到一些东西来观察这两种策略。

标签: mysql performance subquery temp-tables


【解决方案1】:

这实际上取决于。您必须测试每个选项的性能。在我的网站上,我有 2 张桌子,上面有文章和 cmets。事实证明,为每篇文章调用 20 次评论计数比使用单个联合查询要快。 MySQL(与其他数据库一样)缓存查询,因此小的简单查询可以以惊人的速度运行。

【讨论】:

    【解决方案2】:

    我没有看到您已将问题标记为 mysql,所以我最初选择了 Oracle。以下是我对 mySQL 的看法。

    MySQL 临时表内存或磁盘有两种选择。对于磁盘,您可以使用 MyIsam - 非事务性和 InnoDB 事务性。当然,对于非事务类型的存储,您可以期待更好的性能。

    此外,您还需要弄清楚您要处理的结果集有多大。对于小结果集,内存选项会更快,对于大结果集,磁盘选项会更快。

    最后,就像我原来的答案一样,您需要弄清楚什么性能足够好,并选择最具描述性和易于阅读的选项。

    甲骨文

    这取决于您要处理的临时表类型。

    您可以拥有基于会话的临时表 - 数据保留到注销,或基于事务的数据保留到提交。最重要的是,他们可以支持或不支持事务日志记录。根据配置,您可以从临时表中获得更好的性能。

    因为世界上的一切表现都是相对的。很可能对于几千条记录,这两个查询之间不会有显着差异。在这种情况下,我不会选择性能最好的,而是选择最容易阅读和理解的。

    【讨论】:

      【解决方案3】:

      这两个公式是相同的,只是您的显式临时表版本是 3 个 sql 语句而不是只有 1 个。也就是说,来回到服务器的开销使其变慢。但是……

      由于隐式临时表位于 LEFT JOIN 中,因此可以通过以下两种方式之一评估该子查询...

      • 旧版本的 MySQL 被“转储”并重新评估。因此很慢。
      • 较新的版本会自动创建索引。因此很快。

      同时,您可以通过添加合适的索引来加速显式临时表版本。应该是PRIMARY KEY(collegiate_id)。如果INNER JOIN 有可能产生重复,请说SELECT DISTINCT

      对于“几千”行,您通常无需担心性能问题。

      Oracle 有无数种选择。 MySQL 很少,默认(通常)是最好的。因此,请忽略讨论您可以在 MySQL 中使用的各种选项的答案。

      有问题

      AND  IF(notCollegiate,
              c.collegiate_id NOT IN (notCollegiate),
              '1=1')
      

      我不知道notCollegiate 在哪个表中。notCollegiate 不能是列表,那么为什么要使用IN?相反,只需使用!=。最后,'1=1' 是一个 3 个字符的字符串;你真的想要吗?

      为了性能(任一版本)

      • remittances 需要 INDEX(type_id, name, remittance_id)remittance_id 最后。
      • collegiateRemittances 需要INDEX(remittance_id)(除非是PK)。
      • collegiates 需要 INDEX(typePayment, active, exentFee , approvedBoard),顺序不限。

      底线:更关心索引而不是如何制定查询。

      哎哟。另一个皱纹。 getFee() 是什么?如果它是一个存储函数,也许我们需要担心优化它?什么是dateS?

      【讨论】:

        猜你喜欢
        • 2013-02-07
        • 1970-01-01
        • 2016-01-04
        • 2013-10-20
        • 1970-01-01
        • 2013-04-26
        • 2015-03-20
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多