加入 table 时性能缓慢
Slow performance on joining table
我正在尝试如下优化查询,我研究了如何添加索引以提高性能,但结果仍然很慢。下面的查询花了 20 秒到达 运行 ,事务包含大约 100k 条记录并加入 table 包含大约 500k 条记录的 TransactionDetail。
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个索引,
交易(agent_id,distributor_id)和交易(transaction_id)
从 where 子句我添加了 Transaction(status)
- 因为 ORDER BY 我添加了交易(issued_date)
但它没有显示任何改进,下面是我从 EXPLAIN
中得到的
这是来自 phpmyadmin 的屏幕截图,显示了 table 交易
的索引
有什么方法可以改进这个查询吗?或者它已经优化,我应该关注 mysql 配置?
您的查询
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);
添加所有 INDEXes
是徒劳的,因为优化器将(几乎总是)只使用一个索引。
原始查询 可能 受益于 INDEX(issue_date)
。添加该索引,然后向我们展示 EXPLAIN SELECT ...
的输出,看看它是否正在使用它。
如果它正在使用它,那只会通过避免 "filesort" 而受益,这通常只占总时间的一小部分。它也可能因 LIMIT
而停止而受益。但是,它可能必须读取超过 10 行,因为 WHERE
包含其他表。
由于 TransactionDetail.type = 'Admin'
,在决定要保留的行之前,它必须先完成 JOINs
。
两个可能导致其他选项的问题:
- 多少百分比的 TransactionDetail 行具有类型 = 'Admin'?
- 事务行的状态为 IN ('pending'、'processing'、'success'、'rejected')的百分比是多少?
在您进行试验时,post (1) 索引和 (2) EXPLAIN。
我正在尝试如下优化查询,我研究了如何添加索引以提高性能,但结果仍然很慢。下面的查询花了 20 秒到达 运行 ,事务包含大约 100k 条记录并加入 table 包含大约 500k 条记录的 TransactionDetail。
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个索引, 交易(agent_id,distributor_id)和交易(transaction_id)
从 where 子句我添加了 Transaction(status)
- 因为 ORDER BY 我添加了交易(issued_date)
但它没有显示任何改进,下面是我从 EXPLAIN
中得到的这是来自 phpmyadmin 的屏幕截图,显示了 table 交易
的索引有什么方法可以改进这个查询吗?或者它已经优化,我应该关注 mysql 配置?
您的查询
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);
添加所有 INDEXes
是徒劳的,因为优化器将(几乎总是)只使用一个索引。
原始查询 可能 受益于 INDEX(issue_date)
。添加该索引,然后向我们展示 EXPLAIN SELECT ...
的输出,看看它是否正在使用它。
如果它正在使用它,那只会通过避免 "filesort" 而受益,这通常只占总时间的一小部分。它也可能因 LIMIT
而停止而受益。但是,它可能必须读取超过 10 行,因为 WHERE
包含其他表。
由于 TransactionDetail.type = 'Admin'
,在决定要保留的行之前,它必须先完成 JOINs
。
两个可能导致其他选项的问题:
- 多少百分比的 TransactionDetail 行具有类型 = 'Admin'?
- 事务行的状态为 IN ('pending'、'processing'、'success'、'rejected')的百分比是多少?
在您进行试验时,post (1) 索引和 (2) EXPLAIN。