MySql Left加入非常慢的查询

时间:2016-06-28 14:01:44

标签: mysql performance mysql-slow-query-log

我有2张约3000/4000行的表格。我需要使用左连接建立关系,通过搜索文本或日期时间来过滤结果。我还需要计算一整行的分页。当我运行查询是史诗般的慢,请考虑控制台大约40/45秒和网页超过一分钟。 关系是:对于表1中的1,表B中有N. 有一个快速查询的解决方案? 示例查询是:

SELECT X,Y,Z, (SELECT COUNT(*) 
     FROM tableB WHERE tableB.idTa=tableA.id) AS CountTB 
FROM tableA 
LEFT JOIN tableB ON tableA.id = tableB.idA
WHERE tableA.X LIKE'%mytext%' OR tableB.Z LIKE'%mytext%' 
GROUP BY tableA.id 
ORDER BY tableA.Y LIMIT 0,10

谢谢大家

ON条款当然存在。只有我的手机输入错误。现在它是正确的,非常慢:)

新更新: 如果我将关系从LEFT JOIN更改为RIGHT JOIN,它会变得非常快......为什么?

3 个答案:

答案 0 :(得分:2)

从正确的JOIN开始我认为应该可以很快地运作。

类似的东西:

SELECT a.X,a.Y,a.Z, COUNT(b.id)  CountTB 
FROM tableA a
LEFT JOIN tableB b
ON b.idTa = a.id AND b.Z LIKE'%mytext%' 
WHERE a.X LIKE '%mytext%'
GROUP BY tableA.id 
ORDER BY tableA.Y LIMIT 0,10

你的条件不是很清楚。如果您能提供良好的数据样本,我们可以找到更好的查询。

我猜你不需要b.Z LIKE'%mytext%'。从以下开始:

SELECT a.X,a.Y,a.Z, COUNT(b.id)  CountTB 
FROM tableA a
LEFT JOIN tableB b
ON b.idTa = a.id 
WHERE a.X LIKE '%mytext%'
GROUP BY tableA.id 
ORDER BY tableA.Y LIMIT 0,10

答案 1 :(得分:1)

对此进行疯狂的抨击,只是为了指向一般方向,这里是可能的重写该查询:(我不保证它有效......)

SELECT X,Y,Z, COUNT(B.id) AS CountTB
FROM tableA A
  LEFT JOIN tableB B
    USING (id)
WHERE tableA.X LIKE'%mytext%' OR tableB.Z LIKE'%mytext%' 
GROUP BY X, Y, Z
ORDER BY tableA.Y 
LIMIT 0,10

请注意我的许多变化:

  1. 没有嵌套查询。
  2. 这些表格是为方便起见而识别的AB
  3. LEFT JOINUSING (id),是WHERE A.id = B.id的简写。
  4. GROUP BY子句指定数据按这三个变量分组。所有这些必须出现在SELECT子句中,并且显示的所有 else 必须是聚合函数,例如COUNT()SUM()
  5. 同样,我不保证此查询有效。但是它应该说明通常应该如何构造这样的查询。

答案 2 :(得分:0)

请不要使用LEFT,除非您想要使用'右手提供的NULLs&#39}。表。在这种情况下,我不认为你这样做。

( SELECT COUNT... )的定位意味着需要对行进行重新评估,而不是。摆脱它;使用SQL_CALC_FOUND_ROWS

正在搜索A.X和B.Z的相同的子字符串?他们总是有相同的价值吗?如果是这样,那么只搜索其中一个。 (LIKE '%...'是您查询中代价高昂的部分。)

使用JOIN膨胀行数;然后你添加GROUP BY来放气。这种充气/放气是昂贵的。

COUNT(*)无法按'%mytext%'进行过滤,因此无法为您提供所需的内容" 145&#34行30-39 ;

是A.Z还是B.Z ??

SELECT SQL_CALC_FOUND_ROWS
        a.X, a.Y,
        ( SELECT Z FROM tableB WHERE idTa = a.id AND Z LIKE'%mytext%' ) AS Z
    FROM tableA AS a
    WHERE a.X LIKE '%mytext%'
    ORDER BY a.Y
    LIMIT 0,10

SELECT FOUND_ROWS();   -- to get the "of 156 rows"

你需要这些

tableB: INDEX(idTa)
tableA: INDEX(Y)

警告:由于不清楚A和B之间的关系是什么(1:很多与很多:很多),这个解决方案可能不正确。返回多行的子查询将跳出错误。

所以,我可能没有给你正确的'回答,但希望我已经给了你足够的线索,这样你就可以更加接近了。

在那之后,也许你可以通过“记住你离开的地方”来加快分页。而不是使用OFFSET。请参阅my blog

如果您想进一步讨论,请提供SHOW CREATE TABLE并不要混淆列名称 - 通常这些名称会提供您的意图线索。