【问题标题】:Why are my MySQL joins slow?为什么我的 MySQL 连接很慢?
【发布时间】:2014-04-19 03:32:42
【问题描述】:

我有一个连接表的查询。这是选择语句:

SELECT *, A.id AS id, 
       A.username AS username, 
       G.desc AS customer_desc, 
       H.id AS counter, 
       SUM( F.amount_paid ) 
FROM tblcheckin AS A
LEFT OUTER JOIN tblrate AS B ON B.id = A.rate_id
LEFT OUTER JOIN tblrefaccom_type AS C ON C.id = A.id
LEFT OUTER JOIN tblcust_bill AS D ON D.check_in_id = A.id
LEFT OUTER JOIN tblroom AS E ON E.room_no = A.room_id
LEFT OUTER JOIN tblpayment AS F ON F.check_in_id = A.id
LEFT OUTER JOIN tblrefcust_type AS G ON G.id = A.customer_desc
LEFT OUTER JOIN tblindex AS H ON A.id = H.check_in_id
WHERE A.check_out =  "0000-00-00 00:00:00"
GROUP BY F.check_in_id
ORDER BY check_out, check_in

结果:Showing rows 0 - 11 ( 12 total, Query took 7.4061 sec)

这是Explain SQL

这是我到目前为止所做的: 我设置了optimizer_search_depth = 0,因为我认为它会像这里提到的那样工作Joining many tables in mySQL

我在这里做错了什么?我感谢每一个反馈。谢谢。

更新。问题解决了。我从 tblpayment、tblcust_bill 和 tblindex 向 check_in_id 列添加了索引。这是新的Explain SQL

【问题讨论】:

标签: php mysql sql join


【解决方案1】:

查看您的解释,我可以看到有几个连接需要全表扫描。您可能没有对A.check_outD.check_in_idF.check_in_id(基于相对行数的杀手)和H.check_in_id 的索引。这意味着它必须扫描整个该死的表 A、D、F 和 H 以找到相关行。

索引这 4 行,查询时间应该会飙升。

话虽如此,我很惊讶这并没有很快,甚至没有优化。我在每个表中看到了几万行 - 除非这些行真的很大(顺便说一下不好的做法 - 将文本/blob和大列分成单独的表),你应该能够得到这些结果不到 7 秒。更像是我期望的 70 毫秒。我怀疑你必须调整你的 mysql 服务器设置 - 使用更多内存,增加缓冲区大小等。但这些索引应该有很大帮助。

【讨论】:

  • 我认为这是一个伟大的想法,但@OllieJones 提出了一个很好的观点,即加入您甚至没有在下面使用的表格。也看看那个答案!
  • 感谢您的反馈。肯定会尝试修复索引。之后我会发布更新。
  • 如果您不知道如何添加索引,请告诉我们,我相信我们可以帮助您。基本上 ALTER TABLE table ADD KEY( column ) 是你想要做的。
  • 嗨。表 F (tblpayment) 有 23k 行。它与 tblcheckin 具有多对一的关系。它有一个名为 id 的主键。然而,在我的加入声明中,我使用了tblpayment AS F ON F.check_in_id = A.id。还有其他方法吗?通过向 tblpayment、tblcust_bill 和 tblindex 添加索引,查询消耗的时间已减少到 2 秒。但是,被搜索的行是相同的。我做得对吗?
  • 即使tblpaymentcheck_in_id 列中有许多相同的值,您仍然会看到通过索引它显着提高速度。一个表上可以有多个索引,它们不必是唯一的。要回答有关您是否做得对的问题,我们需要查看更新后的说明。
【解决方案2】:

您似乎在左连接许多不需要满足您的查询的表。省去多余的桌子,这行得通吗?

SELECT A.id AS id, 
       A.username AS username, 
       G.desc AS customer_desc, 
       H.id AS counter, 
       SUM( F.amount_paid ) 
FROM tblcheckin AS A
LEFT OUTER JOIN tblpayment AS F ON F.check_in_id = A.id
LEFT OUTER JOIN tblrefcust_type AS G ON G.id = A.customer_desc
LEFT OUTER JOIN tblindex AS H ON A.id = H.check_in_id
WHERE A.check_out =  "0000-00-00 00:00:00"
GROUP BY F.check_in_id
ORDER BY check_out, check_in

您正在使用令人讨厌的 MySQL hackstension 来进行 GROUP BY。改为这样做。

GROUP BY A.id, A.username, G.desc, H.id

tblcheckin 是多行表吗?如果是这样,请确保check_out 上有一个索引,并且声明为NOT NULL

确保在 JOIN 指令中的 ON 子句中提到的列上有索引,即:

   tblpayment.check_in_id
   tblrefcust_type.id   (maybe already a primary key)
   tblindex.check_in_id

考虑在表中放置覆盖索引(多列索引)。这样,您的查询需要的特定查询中的数据可以完全从索引中得到满足,这将节省查询查找磁盘驱动器的时间。不过,很多索引会减慢插入和更新速度。

   tblcheckin (cneck_out, id, customer_desc, username)
   tblpayment  (check_in_id, amount_paid)
   tblrefcust_type  (id, desc)
   tblindex        (check_in_id, id)

【讨论】:

  • 你知道这是一个非常好的观点,B、C、D、E 表似乎根本不重要!
  • 抱歉这个问题。我忘记在选择中包含“*”。我复制了我今天早上一直在测试的查询。我将编辑问题。再次道歉。
猜你喜欢
  • 2011-05-24
  • 1970-01-01
  • 2015-11-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多