我正在开发一个营销型系统。在首页上,其中一项要求是让销售人员看到他们当前拥有的销售机会数量。
即。
Birthdays | 10
Anniversaries | 15
Introductions | 450
Recurring | 249
问题是我正在UNION
所有这些并且在某些情况下查询占用了 10 多秒。 (我们有缓存,所以这只是用户当天第一次登录时的问题)。
还有很多其他的标准:
- 计数中应该只包含每个客户每种类型的最新一个(即,如果一个客户有两个介绍,则应该只计算一次 - 我正在使用 greatest-n-per-group 方法来完成此操作)
- 对于生日和纪念日,日期应该是从今天起 +/- 7 天
- 对于所有这些,只计算过去60天的记录
- 这些记录需要与客户表相结合,以确保机会的销售人员与客户当前的销售人员匹配
这是生成的查询(很长):
SELECT 'Birthdays' AS `type`, COUNT(*) AS `num`
FROM `opportunities`
INNER JOIN `customers`
ON `opportunities`.`customer_id` = `customers`.`customer_id`
AND `opportunities`.`sales_person_id` = `customers`.`sales_person_id`
LEFT JOIN `opportunities` AS `o2`
ON `opportunities`.`customer_id` = `o2`.`customer_id`
AND `opportunities`.`marketing_message` = `o2`.`marketing_message`
AND opportunities.communication_alert_date < o2.communication_alert_date
WHERE ((`opportunities`.`org_code` = ?))
AND (opportunities.marketing_message = 'Birthday Alert')
AND ((opportunities.communication_alert_date BETWEEN
DATE_SUB(NOW(), INTERVAL 7 DAY) AND DATE_ADD(NOW(), INTERVAL 7 DAY)))
AND (opportunities.communication_alert_date >= DATE_SUB(NOW(), INTERVAL 60 DAY))
AND (o2.customer_id IS NULL)
UNION ALL
SELECT 'Anniversaries' AS `type`, COUNT(*) AS `num`
FROM `opportunities`
INNER JOIN `customers`
ON `opportunities`.`customer_id` = `customers`.`customer_id`
AND `opportunities`.`sales_person_id` = `customers`.`sales_person_id`
LEFT JOIN `opportunities` AS `o2`
ON `opportunities`.`customer_id` = `o2`.`customer_id`
AND `opportunities`.`marketing_message` = `o2`.`marketing_message`
AND opportunities.communication_alert_date < o2.communication_alert_date
WHERE ((`opportunities`.`org_code` = ?))
AND (opportunities.marketing_message = 'Anniversary Alert')
AND ((opportunities.communication_alert_date BETWEEN
DATE_SUB(NOW(), INTERVAL 7 DAY) AND DATE_ADD(NOW(), INTERVAL 7 DAY)))
AND (opportunities.communication_alert_date >= DATE_SUB(NOW(), INTERVAL 60 DAY))
AND (o2.customer_id IS NULL)
UNION ALL
SELECT 'Introductions' AS `type`, COUNT(*) AS `num`
FROM `opportunities`
INNER JOIN `customers`
ON `opportunities`.`customer_id` = `customers`.`customer_id`
AND `opportunities`.`sales_person_id` = `customers`.`sales_person_id`
LEFT JOIN `opportunities` AS `o2`
ON `opportunities`.`customer_id` = `o2`.`customer_id`
AND `opportunities`.`marketing_message` = `o2`.`marketing_message`
AND opportunities.communication_alert_date < o2.communication_alert_date
WHERE ((`opportunities`.`org_code` = ?))
AND ((opportunities.Intro_Letter = 'Yes'))
AND (opportunities.communication_alert_date >= DATE_SUB(NOW(), INTERVAL 60 DAY))
AND (o2.customer_id IS NULL)
UNION ALL
SELECT 'Recurring' AS `type`, COUNT(*) AS `num`
FROM `opportunities`
INNER JOIN `customers`
ON `opportunities`.`customer_id` = `customers`.`customer_id`
AND `opportunities`.`sales_person_id` = `customers`.`sales_person_id`
LEFT JOIN `opportunities` AS `o2`
ON `opportunities`.`customer_id` = `o2`.`customer_id`
AND `opportunities`.`marketing_message` = `o2`.`marketing_message`
AND opportunities.communication_alert_date < o2.communication_alert_date
WHERE ((`opportunities`.`org_code` = ?))
AND ((opportunities.marketing_message != 'Anniversary Alert'
AND opportunities.marketing_message != 'Birthday Alert'
AND opportunities.Intro_Letter != 'Yes'))
AND (opportunities.communication_alert_date >= DATE_SUB(NOW(), INTERVAL 60 DAY))
AND (o2.customer_id IS NULL)
我在 opportunities
表中有以下字段的索引:
- 组织代码
- 客户编号
- 介绍信
- 营销信息
- sales_person_id
- org_code, marketing_message
- 组织代码、介绍信
- org_code、marketing_message、Intro_Letter
如果能帮助优化这个,我们将不胜感激。如果需要,我愿意创建其他表或 View 。
最佳答案
一个好的开始是删除字符串比较并将它们放入一个分配了 ID 的表中,并在
的位置添加数字列opportunities.marketing_message != 'Birthday Alert'
所以你会有...
[id] [name]
1 Birthday Alert
2 Anniversary
数字比较总是更快,即使有索引。这样做还可以让您在未来轻松添加新类型。
这部分是多余的,您不需要 AND (opportunities.communication_alert_date >= DATE_SUB(NOW(), INTERVAL 60 DAY))
因为它之前的子句会完成这项工作。
AND ((opportunities.communication_alert_date BETWEEN
DATE_SUB(NOW(), INTERVAL 7 DAY) AND DATE_ADD(NOW(), INTERVAL 7 DAY)))
AND (opportunities.communication_alert_date >= DATE_SUB(NOW(), INTERVAL 60 DAY))
关于sql - 如何优化复杂查询?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4219490/