使用左连接的 MySQL 非常慢的查询

标签 mysql optimization group-by left-join

<分区>

我有一个在相当大的数据集上运行的查询。
非常慢...

我需要优化这个查询,但不确定从哪里开始(除了索引)。

提前致谢!

SELECT d.distributor_id, 
d.first_name,
d.last_name,
d.sponsor_id,
COUNT(f.business_level) AS total_enrollments,
SUM(CASE WHEN UPPER(f.business_level) = 'EXECUTIVE' THEN 1 else 0 end)
    AS executive_enrollments,
SUM(CASE WHEN UPPER(f.business_level) = 'PERSONAL' THEN 1 else 0 end)
    AS personal_enrollments,
SUM(CASE WHEN UPPER(f.business_level) = 'PREFERRED CUSTOMER' THEN 1 else 0 end)
    AS preferred_customer_enrollments,
IFNULL(cf.commission_paid, 0) AS commission_paid,
IFNULL(cf.retention_earned, 0) AS retention_earned,
COUNT(df.order_type) AS total_autoships,
IFNULL(a.consecutive_streak, 0) AS autoship_streak,
IFNULL(a.enrollment_date, "Not Enrolled") AS autoship_enrollment,
d.highest_rank
    FROM warehouse.distributor d
        LEFT JOIN warehouse.enrollment_detail_fact f ON d.distributor_id = f.distributor_id
        LEFT JOIN warehouse.country c ON d.country = c.name
             AND c.country_id = 185
        LEFT JOIN warehouse.autoship a ON d.distributor_id = a.distributor_id
        LEFT JOIN warehouse.order_detail_fact df ON d.distributor_id = df.distributor_id
            AND UPPER(order_type) = 'AUTOSHIP'
            AND date_id IN(SELECT date_id FROM warehouse.date
                WHERE DATE BETWEEN '2012-10-10'
                AND '2012-10-11' ORDER BY date DESC)
        LEFT JOIN warehouse.commission_detail_fact cf ON d.distributor_id = df.distributor_id
        LEFT JOIN db.commission_level_type_details cl ON d.highest_rank = cl.name
WHERE d.active = 1               
    AND cl.commission_level_type_detail_id IN (23)
GROUP BY distributor_id
ORDER BY first_name; 

最佳答案

我会尝试将此 WHERE 子句移动到 JOIN 子句中:

AND cl.commission_level_type_detail_id IN (23)

将其添加到此 JOIN 子句中:

LEFT JOIN db.commission_level_type_details cl ON d.highest_rank = cl.name

对于这个 JOIN 子句:

LEFT JOIN warehouse.order_detail_fact df ON d.distributor_id = df.distributor_id
            AND UPPER(order_type) = 'AUTOSHIP'
            AND date_id IN(SELECT date_id FROM warehouse.date
                WHERE DATE BETWEEN '2012-10-10'
                AND '2012-10-11' ORDER BY date DESC)

我会将此数据结构 *AND UPPER(order_type) = 'AUTOSHIP')* 规范化为“order_type”表,并改用索引整数 ID。效率更高。

我还会将 date_id 去规范化(不确定为什么要规范化记录的日期,也许我遗漏了一些业务需求)。只需将日期放在同一个表中,对其进行索引,然后让 MySQL 做它最擅长的事情。 WHERE 子句中嵌入的 SELECT 没有索引,因此 MySQL 无法最佳地处理该数据。

事实上,我会将 JOIN 和 WHERE 子句中不是 INTEGER 的所有内容标准化。将它们变成整数 ID。这将大大降低性能成本。根据经验,我从不要求数据库服务器对字母数字索引执行查找。

我会根据自己的想法进行编辑和发布。

希望这对您有所帮助。祝你好运。

关于使用左连接的 MySQL 非常慢的查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13201809/

相关文章:

php - 是否可以在单个查询中选择 MonthToDate、LastYearMonthToDate、YearToDate 和 LastYearToDate?

mysql - 从 A 组中选择缺少值的 B 组数据

c# - LINQ 分组依据然后显示 (dd mmm) 的日期时间

php - 如何在mysql中使用带group by的子查询?

php - 何时在 SQL 查询中使用 FOR UPDATE?

ruby - 如何内存一个多维数组的生成方法

MySQL 查询杀死我的服务器

c++ - 可以为了速度牺牲常量正确性吗?

php - PHP 与 MYSQL 的并发

php - 为初学者制作 php 脚本以允许用户访问其信息的指南