加入桌子的表现很慢

时间:2015-06-01 08:32:46

标签: mysql sql performance query-optimization innodb

我正在尝试如下优化查询,我已经研究了如何添加索引以提高性能,但结果仍然很慢。下面的查询需要20秒才能运行,Transaction包含大约100万条记录,并且连接表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

从上面的查询中我尝试应用我对索引的理解

  1. 由于内部连接,我添加了3个索引, 交易(agent_id,distributor_id)和交易(transaction_id)

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

  3. 由于ORDER BY,我添加了Transaction(issued_date)
  4. 但是,我从EXPLAIN

    得到的结果并没有显示出任何改进

    enter image description here

    这是来自phpmyadmin的截图,显示了表Transaction

    的索引

    enter image description here

    有没有办法改进这个查询?或者它已经优化,我应该专注于mysql配置?

2 个答案:

答案 0 :(得分: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);

答案 1 :(得分:1)

添加所有INDEXes是徒劳的,因为优化器(几乎总是)只使用一个索引。

原始查询可能受益于INDEX(issue_date)。添加该索引,然后向我们显示EXPLAIN SELECT ...的输出,看它是否正在使用它。

如果它正在使用它,那只会避免使用" filesort"这通常只占总时间的一小部分。它也可能因LIMIT因停止而受益。但是,它可能必须读取超过10行,因为WHERE包括其他表。

由于TransactionDetail.type = 'Admin',它必须在决定要保留哪些行之前通过JOINs

可能导致其他选项的两个问题:

  • TransactionDetail的行数有多少=' Admin'?
  • 交易行的百分比具有状态IN('待定','处理','成功''拒绝' )?

在进行实验时,发布(1)索引和(2)EXPLAIN。