Mysql Select INNER JOIN with order by very slow

Mysql Select INNER JOIN with order by very slow

我正在尝试加快 mysql 查询。列表 table 有几百万行。如果我稍后不对它们进行排序,我会在 0.1 秒内得到结果,但一旦我排序它需要 7 秒。我可以改进什么来加快查询速度?

SELECT l.* 
FROM listings l 
INNER JOIN listings_categories lc 
ON l.id=lc.list_id 
AND lc.cat_id='2058' 
INNER JOIN locations loc 
ON l.location_id=loc.id 
WHERE l.location_id 
IN (7841,7842,7843,7844,7845,7846,7847,7848,7849,7850,7851,7852,7853,7854,7855,7856,7857,7858,7859,7860,7861,7862,7863,7864,7865,7866,7867,7868,7869,7870,7871,7872,7873,7874,7875,7876,7877,7878,7879,7880,7881,7882,7883,7884,7885,7886,7887,7888,7889,7890,7891,7892,7893,7894,7895,7896,7897,7898,7899,7900,7901,7902,7903) 
ORDER BY date 
DESC LIMIT 0,10;

EXPLAIN SELECT: 使用索引 l=date, loc=primary, lc=primary

这样的性能问题真的很难回答,取决于设置、索引等。因此,可能没有唯一的解决方案,甚至没有真正正确或不正确的提高速度的尝试。这是大量的尝试和错误。无论如何,我注意到一些经常导致性能问题的点是:

  • 避免连接中应该放在 where 中的条件。连接应该只包含将要连接的列,没有其他条件。所以“lc.cat_id='2058”应该放在where子句中。
  • 使用 IN 通常很慢。您可以尝试使用 OR (l.location_id = 7841 OR location_id = 7842 OR...)
  • 来替换它
  • 打开查询执行计划,查看是否有对您有用的东西。
  • 尝试查明受影响的列中是否有特殊的 cases/values 会减慢您的查询速度
  • 将“ORDER BY date”更改为“ORDER BY tablealias.date”并检查这是否会影响性能。就算不会,也比读书好
  • 如果您可以重命名列“日期”,请执行此操作,因为使用 SQL 关键字作为 table 名称或列名称并不是一个好主意。我不确定这是否会影响性能,但应尽可能避免。

祝你好运!

您可以尝试使用附加索引来加快查询速度,但是当 creating/manipulating 数据时,您需要权衡。

这些组合键可以加快查询速度:

listings: date, location_id 
listings_categories: cat_id, list_id

因为计划说它使用日期索引,所以在使用新索引时不需要读取记录来检查 location_id,与 [=19= 的连接也是如此], 索引读就够了

l:  INDEX(location_id, id)
lc:  INDEX(cat_id, list_id)

如果这些还不够,请尝试以下重写。

SELECT  l2.*
    FROM  
    (
        SELECT  l1.id
            FROM  listings AS l1
            JOIN  listings_categories AS lc  ON lc.list_id = l1.id
            JOIN  locations AS loc  ON loc.id = l1.location_id
            WHERE  lc.cat_id='2058'
              AND  l1.location_id IN (7841, ..., 7903)
            ORDER BY  l1.date DESC
            LIMIT  0,10 
    ) AS x
    JOIN  listings l2  ON l1.id = x.id
    ORDER BY  l2.date DESC 

listings:  INDEX(location_id, date, id)
listings_categories:  INDEX(cat_id, list_id)

这里的想法是在到达 table 本身之前从索引中获取 10 个 id。您的版本可能在排序之前将整个 table 铲掉,然后交付 10.