我有一条查询需要几分钟才能运行。它实际上是较大查询的一部分,但是这似乎是瓶颈。我有一个内部选择可能是罪魁祸首。
我正在寻找其他索引或其他重新布置以加快速度。我正在考虑也许将该子选择放入一个临时表中,除了它使用where子句中外部查询的数据外,否则将不起作用。
以下是查询:
SELECT principalid, count(*) AS CRs_used FROM
(
SELECT crMan.principalid, crMan.repid, MIN(crMan.daterequest) as FirstContactDate
FROM contactrequest crMan
INNER JOIN principal p
ON crMan.principalid = p.userid
WHERE
initiatedby = 2
AND status <> 'C'
AND NOT EXISTS
(
SELECT *
FROM contactrequest crRep
WHERE crMan.principalid = crRep.principalid
AND crMan.repid = crRep.repid
AND initiatedby = 1
AND status <> 'C'
AND crRep.daterequest < crMan.daterequest
)
GROUP BY userid, crMan.principalid, crMan.repid) AS ContactRequestsThatCount GROUP BY principalid;
模式:
CREATE TABLE `principal` (
`operid` mediumint(8) unsigned NOT NULL DEFAULT 0,
`ts` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
`userid` mediumint(8) unsigned NOT NULL DEFAULT 0,
`targetcustomer` varchar(8000) NOT NULL DEFAULT '',
`targetcustomer_stemmed` varchar(10000) NOT NULL DEFAULT '',
`productline` varchar(8000) NOT NULL DEFAULT '',
`productline_stemmed` varchar(10000) NOT NULL DEFAULT '',
`salesopportunity` varchar(8000) NOT NULL DEFAULT '',
`salesopportunity_stemmed` varchar(10000) NOT NULL DEFAULT '',
`annualsales` decimal(11,0) DEFAULT NULL,
`marketingassistance` bit(1) DEFAULT NULL,
`trainingprovided` bit(1) DEFAULT NULL,
`exclusiveterritories` bit(1) DEFAULT NULL,
`repagency` bit(1) DEFAULT NULL,
`made_in_usa` bit(1) DEFAULT NULL,
`established_line` bit(1) DEFAULT NULL,
PRIMARY KEY (`userid`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
CREATE TABLE `contactrequest` (
`operid` mediumint(8) unsigned NOT NULL DEFAULT 0,
`ts` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
`contactrequestid` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
`repid` mediumint(8) unsigned NOT NULL DEFAULT 0,
`principalid` mediumint(8) unsigned NOT NULL DEFAULT 0,
`initiatedby` tinyint(3) unsigned NOT NULL DEFAULT 0,
`response` char(1) NOT NULL DEFAULT '',
`reasonid` tinyint(3) unsigned NOT NULL DEFAULT 0,
`status` char(1) NOT NULL DEFAULT '',
`daterequest` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`dateresponse` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`archivebypri` tinyint(1) NOT NULL DEFAULT 0,
`archivebyrep` tinyint(1) NOT NULL DEFAULT 0,
PRIMARY KEY (`contactrequestid`),
KEY `ix_contactrequest_repid_request` (`repid`,`daterequest`),
KEY `ix_contactrequest_principalid_request` (`principalid`,`daterequest`)
) ENGINE=InnoDB AUTO_INCREMENT=851354 DEFAULT CHARSET=latin1
这是EXPLAIN输出:
编辑:
查询的目的如下: contactrequest表包含我们网站的两个成员之间的联系记录,表示为负责人和代表。双方均可发起请求; initialby = 1表示代表已启动; initialby = 2表示委托人已启动。在每对原理和代表之间可以有多个这样的记录。
该查询计算从委托人到代表的联系数量,但是没有从代表到具有较早时间戳记的委托人的联系。此外,状态为'C'的行也会被忽略。
下面的答案中建议的索引已经部分包含在内。状态索引和initialby索引不是因为根据SQL文档,不应该使用基数较低的索引。 initialby仅在(1、2)中具有值,而在('C','N','')中具有状态。因此基数非常低。
编辑2:
查看原始查询和答案之后,这个问题没有意义,我认为SQL已更改。这样做的证据是-的建议中包含某些内容,除非原始查询中存在该内容。因此,我将把原始查询修改回我认为应该的样子。
问题在于最后一行的一部分在渲染的问题中不可见,但是当您尝试编辑时,实际上那里是正确的文本。我将尝试获取它,以便您可以在格式化的代码中看到它。
答案 0 :(得分:0)
您可以从简化查询开始:
SELECT principalid, COUNT(DISTINCT userid, repid) AS CRs_used
FROM contactrequest crMan INNER JOIN
principal p
ON crMan.principalid = p.userid
WHERE initiatedby = 2 AND
status <> 'C' AND
NOT EXISTS (SELECT 1
FROM contactrequest crRep
WHERE crMan.principalid = crRep.principalid AND
crMan.repid = crRep.repid AND
initiatedby = 1 AND
status <> 'C' AND
crRep.daterequest < crMan.daterequest
)
GROUP BY principalid;
您要在contactrequest(repid, initiatedby, status, daterequest)
上建立索引。
有关该查询及其应做的工作的更多信息,您可能可以做的更多。
答案 1 :(得分:0)
您在这里不需要子查询,select case
应该可以处理。如果您的not exists
子句中符合条件,则将date
的最大值设置为'9999-12-31'
不会成为min()
函数的候选对象
SELECT principalid, count(*) AS CRs_used FROM
(
SELECT crMan.principalid, crMan.repid
, min(case when crMan.principalid = p.principalid
and initiatedby = 1
and status <> 'C'
then '9999-12-31'
when initiatedby = 2 and status <> 'C'
then crMan.daterequest
else crMan.daterequest end)
as FirstContactDate
FROM contactrequest crMan
INNER JOIN principal p
ON crMan.principalid = p.userid
WHERE initiatedby = 2 AND status <> 'C'
GROUP BY userid, crMan.principalid, crMan.repid) AS ContactRequestsThatCount