我试图为每个领导者抓住最近的活动'。我已创建索引,此查询仍将花费超过30分钟。
SELECT l.id,
l.home_number,
l.mobile_number,
CASE WHEN l.soldprice < 2 THEN 0 ELSE 1 END as sold,
l.lead_date
FROM (
SELECT l.home_number, MAX(l.id) as id
FROM lead l
WHERE l.lead_date >= DATE_SUB(NOW(), INTERVAL 52 WEEK)
AND l.state NOT IN ('NY','AR','VT','WV','GA','CT','DC','SD')
GROUP BY l.home_number) a
JOIN lead l ON l.id=a.id;
我的表索引如下:
Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_typ
lead 0 PRIMARY 1 id A 63123648 NULL NULL BTREE
lead 1 id 1 id A 63266540 NULL NULL BTREE
lead 1 soldprice 1 soldprice A 14715 NULL NULL YES BTREE
lead 1 lead_date 1 lead_date A 15351477 NULL NULL YES BTREE
我的表架构:
CREATE TABLE lead
(
id BIGINT unsigned NOT NULL,
lead_date DATETIME NULL,
first_name VARCHAR(50) NULL,
last_name VARCHAR(50) NULL,
hashed_ssn VARCHAR(34) NULL,
city VARCHAR(50) NULL,
state VARCHAR(2) NULL,
home_number VARCHAR(10) NULL,
mobile_number VARCHAR(10) NULL,
email VARCHAR(255) NULL,
soldprice DECIMAL(5,2) NULL,
requested_amount INT NULL,
time_zone VARCHAR(5),
camp_id VARCHAR(9),
leadtype_id VARCHAR(3),
hittype_id VARCHAR(3),
PRIMARY KEY (id)
);
任何建议都将不胜感激。
编辑:我使用的是MySQL 5.7.19-0ubuntu0.16.04.1
答案 0 :(得分:1)
Tl; dr您需要一个复合(多列)索引。
专业提示:除非您知道需要,否则不要创建大量单列索引。它们很少在复杂查询中提供帮助,并且会减慢插入和更新的速度。
您已经很好地使用子查询来获取要获取的行的.row > div {
border: 1px solid black;
}
.vertical-center .row {
display: flex;
align-items: center;
}
/*maybe create an id instead of h1*/
h1 {
margin: 0;
}
值。当然,大部分时间都进入你的子查询,这个:
id
调试子查询通常很聪明,然后将它们加入主查询中。
首先要做的是:在SELECT l.home_number, MAX(l.id) as id
FROM lead l
WHERE l.lead_date >= DATE_SUB(NOW(), INTERVAL 52 WEEK)
AND l.state NOT IN ('NY','AR','VT','WV','GA','CT','DC','SD')
GROUP BY l.home_number
上创建一个复合索引。然后运行这个简化的子查询,省略对状态的排除。这应该很快,因为它可以随机访问日期,然后使用索引来处理分组,并使用松散的索引扫描来获取最大id值。
(lead_date, home_number, id)
接下来,尝试在SELECT l.home_number, MAX(l.id) as id
FROM lead l
WHERE l.lead_date >= DATE_SUB(NOW(), INTERVAL 52 WEEK)
GROUP BY l.home_number
上创建复合索引并尝试原始查询。如果速度相当快,你就完成了。您的查询会更快。删除第一个复合索引。
但它可能不是,因为MySQL在高容量的(lead_date, state, home_number, id)
条款中并不是很好。
在这种情况下,保留第一个复合索引并删除第二个复合索引,并将状态排除移动到外部查询。
这将是这样的:
NOT IN
这应该有所帮助。
http://use-the-index-luke.com/是这类工作的一个很好的参考。
答案 1 :(得分:0)
由于您的子查询具有条件,这是一个棘手的优化查询。
作为一般规则,您可以使用索引来优化某些条件,但只能使用一个范围谓词或GROUP BY或ORDER BY。
但是你有两个范围谓词和一个GROUP BY:
l.lead_date >= DATE_SUB(NOW(), INTERVAL 52 WEEK)
l.state NOT IN ('NY','AR','VT','WV','GA','CT','DC','SD')
GROUP BY l.home_number
您可以使用lead_date
上的索引来缩小行选择范围。您可以使用state
上的索引来缩小行选择范围。或者,您可以使用索引来帮助按组顺序读取查询,并尝试避免使用临时表。 但在给定查询中,您只能拥有这三种优化中的一种。
然后诀窍就是选择你要优先考虑哪一个。它归结为每个人在给定数据分布的情况下改进查询的程度。这取决于您的数据,这不是我们可以回答的问题。因此,您必须使用EXPLAIN测试所有三种情况,或者只运行带有分析的查询以查看它有多大帮助。
通常,使用范围谓词缩小到最小的行子集。然后,即使其他范围谓词和GROUP BY必须在没有索引帮助的情况下工作,它们只需要处理较小的行集,因此总成本不是那么糟糕(希望如此)。
答案 2 :(得分:0)
我正在走出困境并对数据做出一些假设。
SELECT l.id, l.home_number, l.mobile_number,
(l.soldprice < 2) as sold,
l.lead_date
FROM
(
SELECT l.home_number, MAX(l.id) as maxid
FROM lead l
GROUP BY l.home_number
) a
JOIN lead l ON l.id = a.maxid;
WHERE l.lead_date >= DATE_SUB(NOW(), INTERVAL 52 WEEK)
AND l.state NOT IN ('NY','AR','VT', 'WV','GA','CT','DC', 'SD' )
并且
INDEX(home_number, id)
假设:
WHERE
之前运行子查询。 (如果失败,请将其更改为HAVING
。)home_number
都特定于特定的state
。让我们知道这是否会得到相同的结果,但要快得多。