Mysql 更高效的分组方式,用于带有案例的查询
下面的查询构建了一个记录集,该记录集在饼图中用作报告 它并不经常运行,但当它运行时需要几秒钟,我想知道是否有任何方法可以提高它的效率Mysql 更高效的分组方式,用于带有案例的查询,mysql,performance,group-by,Mysql,Performance,Group By,下面的查询构建了一个记录集,该记录集在饼图中用作报告 它并不经常运行,但当它运行时需要几秒钟,我想知道是否有任何方法可以提高它的效率 SELECT CASE WHEN (lastStatus IS NULL) THEN 'Unused' WHEN (attempts > 3 AND callbackAfter IS NULL) THEN 'Max Attempts Reached' WHEN (callbackAfter IS NOT NULL AN
SELECT
CASE
WHEN (lastStatus IS NULL) THEN 'Unused'
WHEN (attempts > 3 AND callbackAfter IS NULL) THEN 'Max Attempts Reached'
WHEN (callbackAfter IS NOT NULL AND callbackAfter > DATE_ADD(NOW(), INTERVAL 7 DAY)) THEN 'Call Back After 7 Days'
WHEN (callbackAfter IS NOT NULL AND callbackAfter <= DATE_ADD(NOW(), INTERVAL 7 DAY)) THEN 'Call Back Within 7 Days'
WHEN (archived = 0) THEN 'Call Back Within 7 Days'
ELSE 'Spoke To'
END AS statusSummary,
COUNT(leadId) AS total
FROM
CO_Lead
WHERE
groupId = 123
AND
deleted = 0
GROUP BY
statusSummary
ORDER BY
total DESC;
尝试删除索引以查看这是否会提高性能 在某些数据库中,索引不一定能提高性能。如果您有索引,MySQL将始终使用它。在这种情况下,这意味着它将读取索引,然后必须从每个页面读取数据。页面读取是随机的,而不是顺序的。对于无论如何都必须读取所有页面的查询,这种随机读取会降低性能。注意:
leadId
不能为NULL
,则将COUNT(leadId)
更改为COUNT(*)
。它们在逻辑上是等价的,但MySQL优化器的大多数版本并不能很好地识别这一点callbackAfter IS NOT NULL
条件。如果callbackAfter
满足第二部分,则无论如何不能为null案例
中的条件是否重叠,您可能会得到错误或正确的结果leadID
列中是否有空值?否,leadID是主键(自动递增)您可以添加表定义吗?谢谢@ypercube,我尝试了类似于您的查询的方法,但错过了添加额外索引的步骤。你的另外两点帮助我整理代码。不过,我可能会先尝试广域覆盖索引,看看这是否有区别。您还可以检查5个子查询中的每一个子查询,看看它们是否真正等同于CASE
表达式。我会将它们写为等价的,但条件会更复杂,不可搜索。谢谢,不幸的是,使用此表时有几件事情需要索引,因此我无法将它们全部删除,删除一些可能会导致使用比当前效率更低的索引。但我认为这值得为其他人尝试。
CREATE TABLE CO_Lead (
objectId int UNSIGNED NOT NULL AUTO_INCREMENT,
groupId int UNSIGNED NOT NULL,
numberToCall varchar(20) NOT NULL,
firstName varchar(100) NOT NULL,
lastName varchar(100) NOT NULL,
attempts tinyint NOT NULL default 0,
callbackAfter datetime NULL,
lastStatus varchar(30) NULL,
createdDate datetime NOT NULL,
archived bool NOT NULL default 0,
deleted bool NOT NULL default 0,
PRIMARY KEY (
objectId
)
) ENGINE = InnoDB;
ALTER TABLE CO_Lead ADD CONSTRAINT UQIX_CO_Lead UNIQUE INDEX (
objectId
);
ALTER TABLE CO_Lead ADD INDEX (
groupId,
archived,
deleted,
callbackAfter,
attempts
);
ALTER TABLE CO_Lead ADD INDEX (
groupId,
deleted,
createdDate,
lastStatus
);
ALTER TABLE CO_Lead ADD INDEX (
firstName
);
ALTER TABLE CO_Lead ADD INDEX (
lastName
);
ALTER TABLE CO_Lead ADD INDEX (
lastStatus
);
ALTER TABLE CO_Lead ADD INDEX (
createdDate
);
SELECT
cnt1 AS "Unused"
, cnt2 AS "Max Attempts Reached"
, cnt3 AS "Call Back After 7 Days"
, cnt4 AS "Call Back Within 7 Days"
, cnt5 AS "Call Back Within 7 Days"
, cnt6 - (cnt1+cnt2+cnt3+cnt4+cnt5) AS "Spoke To"
FROM
( SELECT
( SELECT COUNT(*) FROM CO_Lead
WHERE groupId = 123 AND deleted = 0
AND lastStatus IS NULL
) AS cnt1
, ( SELECT COUNT(*) FROM CO_Lead
WHERE groupId = 123 AND deleted = 0
AND attempts > 3 AND callbackAfter IS NULL
) AS cnt2
, ( SELECT COUNT(*) FROM CO_Lead
WHERE groupId = 123 AND deleted = 0
AND callbackAfter > DATE_ADD(NOW(), INTERVAL 7 DAY)
) AS cnt3
, ( SELECT COUNT(*) FROM CO_Lead
WHERE groupId = 123 AND deleted = 0
AND callbackAfter <= DATE_ADD(NOW(), INTERVAL 7 DAY)
) AS cnt4
, ( SELECT COUNT(*) FROM CO_Lead
WHERE groupId = 123 AND deleted = 0
AND archived = 0
) AS cnt5
, ( SELECT COUNT(*) FROM CO_Lead
WHERE groupId = 123 AND deleted = 0
) AS cnt6
) AS tmp ;
(groupId, deleted, lastStatus, callbackAfter, attempts, archived)