繁体   English   中英

如何通过多个连接加速MySQL查询

[英]How can I speed up MySQL query with multiple joins

这是我的问题,我正在选择并进行多次连接以获得正确的项目...它会提取相当数量的行,超过100,000。 当日期范围设置为1年时,此查询需要超过5分钟。

我不知道是否可能,但我担心用户可能会将日期范围延长至十年并使其崩溃。

谁知道我怎么能加快速度呢? 这是查询。

SELECT DISTINCT t1.first_name, t1.last_name, t1.email 
FROM table1 AS t1 
INNER JOIN table2 AS t2 ON t1.CU_id = t2.O_cid 
INNER JOIN table3 AS t3 ON t2.O_ref = t3.I_oref 
INNER JOIN table4 AS t4 ON t3.I_pid = t4.P_id 
INNER JOIN table5 AS t5 ON t4.P_cat = t5.C_id 
WHERE t1.subscribe =1 
AND t1.Cdate >= $startDate
AND t1.Cdate <= $endDate
AND t5.store =2

我不是最好的mysql所以任何帮助将不胜感激!

提前致谢!

UPDATE

这是你要求的解释

id  select_type     table   type    possible_keys   key     key_len     ref     rows    Extra
1   SIMPLE  t5  ref     PRIMARY,C_store_type,C_id,C_store_type_2    C_store_type_2  1   const   101     Using temporary
1   SIMPLE  t4  ref     PRIMARY,P_cat   P_cat   5   alphacom.t5.C_id    326     Using where
1   SIMPLE  t3  ref     I_pid,I_oref    I_pid   4   alphacom.t4.P_id    31   
1   SIMPLE  t2  eq_ref  O_ref,O_cid     O_ref   28  alphacom.t3.I_oref  1    
1   SIMPLE  t1  eq_ref  PRIMARY     PRIMARY     4   alphacom.t2.O_cid   1   Using where

我还为table5行和table4行添加了一个索引,因为它们并没有真正改变,但是其他表每月大约有500-1000个条目......我听说你应该为一个包含许多新条目的表添加一个索引....这是真的?

我试试以下内容:

首先,确保以下表和列上有索引(括号中的每组列应该是一个单独的索引):

table1 : (subscribe, CDate)
         (CU_id)
table2 : (O_cid)
         (O_ref)
table3 : (I_oref)
         (I_pid)
table4 : (P_id)
         (P_cat)
table5 : (C_id, store)

其次, 如果添加上述索引并没有像你想的那样改进,请尝试将查询重写为

SELECT DISTINCT t1.first_name, t1.last_name, t1.email FROM
  (SELECT CU_id, t1.first_name, t1.last_name, t1.email
     FROM table1
     WHERE subscribe = 1 AND
           CDate >= $startDate AND
           CDate <= $endDate) AS t1
  INNER JOIN table2 AS t2
    ON t1.CU_id = t2.O_cid   
  INNER JOIN table3 AS t3
    ON t2.O_ref = t3.I_oref   
  INNER JOIN table4 AS t4
    ON t3.I_pid = t4.P_id   
  INNER JOIN (SELECT C_id FROM table5 WHERE store = 2) AS t5
    ON t4.P_cat = t5.C_id

我希望这里第一个子选择会显着减少要考虑加入的行数,希望使后续连接做得更少。 同样在table5上第二个子选择背后的推理。

无论如何,搞乱它。 我的意思是,最终它只是一个SELECT - 你不能用它真的伤害任何东西。 检查每个不同排列产生的计划,并试图找出每个排列的好坏。

分享和享受。

确保您的日期列和您加入的所有列都已编入索引。

在你的日期做一个不等的运算符意味着它检查每一行,这本质上比等价的慢。

此外,使用DISTINCT可以为优化程序在后台运行的逻辑添加额外的比较。 如果可能的话,消除它。

好吧,首先,创建一个子查询来将table1抽取到你真正想要加入的所有麻烦的记录......

SELECT DISTINCT t1.first_name, t1.last_name, t1.email  
FROM (  
SELECT first_name, last_name, email, CU_id FROM table1 WHERE  
table1.subscribe = 1  
AND table1.Cdate >= $startDate  
AND table1.Cdate <= $endDate  
) AS t1  
INNER JOIN table2 AS t2 ON t1.CU_id = t2.O_cid  
INNER JOIN table3 AS t3 ON t2.O_ref = t3.I_oref  
INNER JOIN table4 AS t4 ON t3.I_pid = t4.P_id  
INNER JOIN table5 AS t5 ON t4.P_cat = t5.C_id  
WHERE t5.store = 2

然后开始考虑修改连接的方向性。

另外,如果t5.store只是极少数2,那么请翻转这个想法:构造t5子查询,然后将它连接回来,然后返回。

目前,您的查询返回table2-table5上的所有匹配行,只是为了确定t5.store = 2.如果table2-table5中的任何一行具有比table1高得多的行数,这可能会大大增加处理的行数- 因此,以下查询可能会表现得更好:

SELECT DISTINCT t1.first_name, t1.last_name, t1.email 
FROM table1 AS t1 
WHERE t1.subscribe =1 
AND t1.Cdate >= $startDate
AND t1.Cdate <= $endDate
AND EXISTS
(SELECT NULL FROM table2 AS t2
INNER JOIN table3 AS t3 ON t2.O_ref = t3.I_oref 
INNER JOIN table4 AS t4 ON t3.I_pid = t4.P_id 
INNER JOIN table5 AS t5 ON t4.P_cat = t5.C_id AND t5.store =2
WHERE t1.CU_id = t2.O_cid);

尝试在您加入的字段上添加索引。 它可能会也可能不会改善性能。

此外,它还取决于您使用的引擎。 如果您使用的是InnoDB,请检查您的配置参数。 我遇到了类似的问题,因为innodb的默认配置不会像myisam的默认配置那样扩展。

正如大家所说,确保你有索引。

您还可以检查服务器是否已正确设置,以便它可以包含更多内存中的整个数据集。

没有EXPLAIN,就没有多少工作了。 还要记住,MySQL将查看您的JOIN,并在执行查询之前迭代所有可能的解决方案,这可能需要一些时间。 从EXPLAIN获得最佳JOIN顺序后,您可以尝试在查询中强制执行此顺序,从而从优化程序中删除此步骤。

听起来你应该考虑提供子集(分页)或以其他方式限制结果,除非有一个原因是用户一次需要所有可能的行。 通常100K行比普通人可以消化的多。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM