加入 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

根据上面的查询,我尝试应用我对索引的理解

  1. 因为内连接我加了3个索引, 交易(agent_id,distributor_id)和交易(transaction_id)

  2. 从 where 子句我添加了 Transaction(status)

  3. 因为 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。