加入表时性能缓慢
Posted
技术标签:
【中文标题】加入表时性能缓慢【英文标题】:Slow performance on joining table 【发布时间】:2015-06-01 08:32:46 【问题描述】:我正在尝试优化如下查询,我研究了如何添加索引以提高性能,但结果仍然很慢。下面的查询运行了 20 秒,Transaction 包含大约 100k 条记录,连接表 TransactionDetail 包含大约 500k 条记录。
SELECT Transaction.id ....
FROM Transaction
INNER JOIN Agent ON Agent.id = Transaction.agent_id
INNER JOIN Distributor ON Distributor.id = Transaction.distributor_id
INNER JOIN TransactionDetail ON Transaction.id = TransactionDetail.transaction_id
WHERE TransactionDetail.type = 'Admin'
AND Transaction.status IN ('pending', 'processing', 'success', 'rejected')
ORDER BY issued_date DESC LIMIT 0 , 10
从上面的查询中,我尝试应用我对索引的理解
由于内部连接,我添加了 3 个索引, Transaction(agent_id,distributor_id) 和 Transaction(transaction_id)
从 where 子句中我添加了 Transaction(status)
由于 ORDER BY 我添加了 Transaction(issued_date)但它没有显示出任何改进,这是我从 EXPLAIN 中得到的
这是来自 phpmyadmin 的屏幕截图,显示了表事务的索引
有没有办法改进这个查询?或者它已经优化了,我应该专注于 mysql 配置?
【问题讨论】:
如果您认为我应该添加更多信息,请给我写评论 【参考方案1】:您的查询
SELECT Transaction.id ....
FROM Transaction
INNER JOIN Agent ON Agent.id = Transaction.agent_id
INNER JOIN Distributor ON Distributor.id = Transaction.distributor_id
INNER JOIN TransactionDetail ON Transaction.id = TransactionDetail.transaction_id
WHERE TransactionDetail.type = 'Admin'
AND Transaction.status IN ('pending', 'processing', 'success', 'rejected')
ORDER BY issued_date DESC LIMIT 0 , 10
现在您已经在表上应用了索引,这很好,但是in clause
更像or
这会产生一个真正的性能问题。在小数据集的情况下,这无法观察到,但在大数据集中
性能会大幅下降。
优化它的一种方法是将in clause
转换为union
,它比or
in
效果更好
(
SELECT Transaction.id ....
FROM Transaction
INNER JOIN Agent ON Agent.id = Transaction.agent_id
INNER JOIN Distributor ON Distributor.id = Transaction.distributor_id
INNER JOIN TransactionDetail ON Transaction.id = TransactionDetail.transaction_id
WHERE TransactionDetail.type = 'Admin'
AND Transaction.status = 'pending'
)
union
(
SELECT Transaction.id ....
FROM Transaction
INNER JOIN Agent ON Agent.id = Transaction.agent_id
INNER JOIN Distributor ON Distributor.id = Transaction.distributor_id
INNER JOIN TransactionDetail ON Transaction.id = TransactionDetail.transaction_id
WHERE TransactionDetail.type = 'Admin'
AND Transaction.status = 'processing'
)
union
(
SELECT Transaction.id ....
FROM Transaction
INNER JOIN Agent ON Agent.id = Transaction.agent_id
INNER JOIN Distributor ON Distributor.id = Transaction.distributor_id
INNER JOIN TransactionDetail ON Transaction.id = TransactionDetail.transaction_id
WHERE TransactionDetail.type = 'Admin'
AND Transaction.status = 'success'
)
union
(
SELECT Transaction.id ....
FROM Transaction
INNER JOIN Agent ON Agent.id = Transaction.agent_id
INNER JOIN Distributor ON Distributor.id = Transaction.distributor_id
INNER JOIN TransactionDetail ON Transaction.id = TransactionDetail.transaction_id
WHERE TransactionDetail.type = 'Admin'
AND Transaction.status = 'rejected'
)
order by issued_date DESC LIMIT 0 , 10
为了解决订单,您可能需要将索引添加为
alter table Transaction add index status_created_idx(status,issued_date);
【讨论】:
这很好,只是这是一个小数据集。 @Strawberry 对于在status
和issued_date
上有索引的小数据集可以解决问题,即使是10 万条记录,我可以告诉你结果应该在0.2
秒内返回最大。
你错过了一部分issued_date
;) 其余 100% 同意。
我已经尝试重写我的代码,但它几乎没有改进,有没有其他方法可以改进它?
您可以尝试您的原始查询,但请确保您的索引为alter table Transaction add index status_created_idx(status,issued_date);
备份表并应用索引,然后查看性能。【参考方案2】:
添加所有INDEXes
是徒劳的,因为优化器将(几乎总是)只使用一个索引。
原始查询可能受益于INDEX(issue_date)
。添加该索引,然后向我们展示EXPLAIN SELECT ...
的输出,看看它是否正在使用它。
如果它正在使用它,那只会通过避免“文件排序”而受益,这通常只是总时间的一小部分。由于LIMIT
,它也可能受益于停止。但是,它可能必须读取超过 10 行,因为 WHERE
包含其他表。
由于TransactionDetail.type = 'Admin'
,它必须通过JOINs
才能决定保留哪些行。
可能导致其他选择的两个问题:
TransactionDetail 的行中有多少百分比具有 type = 'Admin'? Transaction 行的状态为 IN(“待处理”、“处理中”、“成功”、“已拒绝”)的百分比是多少?在您进行实验时,发布 (1) 索引和 (2) EXPLAIN。
【讨论】:
以上是关于加入表时性能缓慢的主要内容,如果未能解决你的问题,请参考以下文章