如何优化此查询n+1 和dense_rank 之后

问题描述

如何优化此查询

WITH stats AS (SELECT a.IntegratorSalesAssociateID,a.AgentName,(
                          SELECT COUNT(*)
                          FROM properties AS p
                          WHERE a.IntegratorSalesAssociateID = p.IntegratorSalesAssociateID
                            AND p.TransactionType = '2'
                            AND MONTH(p.OrigListingDate) = MONTH(CURRENT_DATE)
                            AND YEAR(p.OrigListingDate) = YEAR(CURRENT_DATE)
                      ) AS properties_this_month
               FROM agents AS a)
SELECT stats.*,DENSE_RANK() over (ORDER BY stats.properties_this_month DESC) AS 'rank'
from stats

我想也许如果我加入两个表并以某种方式对它们进行分组,它会表现得更好,目前它运行了 17.5 秒,奇怪的是,添加dense_rank 根本不会影响性能

相关表结构

CREATE TABLE `agents`
(
    `IntegratorSalesAssociateID` varchar(15) COLLATE utf8mb4_unicode_ci NOT NULL,`AgentName`                  varchar(100) COLLATE utf8mb4_unicode_ci     DEFAULT NULL,`created_at`                 timestamp                              NULL DEFAULT NULL,`updated_at`                 timestamp                              NULL DEFAULT NULL
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8mb4
  COLLATE = utf8mb4_unicode_ci;


CREATE TABLE `properties`
(
    `id`                         bigint(20) UNSIGNED                    NOT NULL,`IntegratorSalesAssociateID` varchar(13) COLLATE utf8mb4_unicode_ci NOT NULL,`TransactionType`            tinyint(4)                             NOT NULL,`OrigListingDate`            date                                        DEFAULT NULL,`updated_at`                 timestamp                              NULL DEFAULT NULL
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8mb4
  COLLATE = utf8mb4_unicode_ci;

解决方法

你可以试试这个:

;WITH stats AS
(
    SELECT 
       p.IntegratorSalesAssociateID,COUNT(*) AS properties_this_month
    FROM properties AS p
    WHERE p.TransactionType = '2'
        AND MONTH(p.OrigListingDate) = MONTH(CURRENT_DATE)
        AND YEAR(p.OrigListingDate) = YEAR(CURRENT_DATE)
    GROUP BY p.IntegratorSalesAssociateID
)
SELECT 
   a.IntegratorSalesAssociateID,a.AgentName,COALESCE(s.properties_this_month,0) AS properties_this_month
FROM agents AS a
LEFT JOIN stats s ON a.IntegratorSalesAssociateID = s.IntegratorSalesAssociateID
,

鉴于 DENSE_RANK() 不影响性能,您想要优化:

SELECT a.IntegratorSalesAssociateID,(SELECT COUNT(*)
        FROM properties p
        WHERE a.IntegratorSalesAssociateID = p.IntegratorSalesAssociateID AND
              p.TransactionType = '2' AND
              MONTH(p.OrigListingDate) = MONTH(CURRENT_DATE) AND
              YEAR(p.OrigListingDate) = YEAR(CURRENT_DATE)
         ) AS properties_this_month
FROM agents a;

我会改写为:

SELECT a.IntegratorSalesAssociateID,(SELECT COUNT(*)
        FROM properties p
        WHERE a.IntegratorSalesAssociateID = p.IntegratorSalesAssociateID AND
              p.TransactionType = 2 AND
              p.OrigListingDate >= CURRENT_DATE - INTERVAL (1 - DAY(CURRENT_DATE) DAY
         ) AS properties_this_month
FROM agents a;

两个变化是:

  • TransactionType 看起来像一个数字。假设是这样,我删除了单引号。不要混合数据类型!当然,如果列是字符串,那就用单引号。
  • 我更改了日期逻辑以删除列上的所有函数。我假设没有未来的“原始”日期。如果是这样,您可以为月底添加另一个条件。

然后,对于这个查询,您需要一个索引:properties(IntegratorSalesAssociateID,TransactionType,OrigListingDate)。实际上,该索引可能适用于数据的原始版本。

我真诚地怀疑使用显式聚合会提高性能。 GROUP BY——虽然非常强大——通常比相关子查询慢。并且使用正确的索引几乎总是变慢(或至少不会变快)。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...