由于ORDER BY不使用索引,因此SQL查询速度慢

时间:2010-12-02 14:48:00

标签: sql mysql database performance

我有这个问题:

SELECT cl.title, cl.URL, cl.ID AS ad_id, cl.cat_id, cl.price, cs.name AS cat_name, pix.file_name, area.area_name 
FROM classifieds cl 
FORCE INDEX (advertiser_id) 
INNER JOIN classifieds_pix pix ON cl.ID = pix.classified_id 
INNER JOIN cat_names_sub cs ON cl.cat_id = cs.ID 
INNER JOIN zip_codes zip ON cl.zip_id = zip.zip_id 
INNER JOIN area_names area ON zip.area_id = area.id 
WHERE cl.confirmed = 1 AND cl.price != '' AND cl.country = 'de' 
GROUP BY cl.advertiser_id
ORDER BY cl.timestamp DESC 
LIMIT 5

需要> classifieds包含168k行时为1秒,这太长了。 FORCE INDEX (advertiser_id)允许我在没有ORDER BY子句的情况下将其降低到0.00x秒。 timestamp列也已编入索引,我尝试添加FORCE INDEX (timestamp),但它没有帮助。

EXPLAINUsing where; Using temporary; Using filesort表的第一个SELECT上说classifieds - 这显然会导致性能问题。

你可以帮我解决这个问题吗?

提前致谢!

PS:此查询的目的是获取5个最新的分类广告(包括一些其他信息,如图片,类别,邮政编码和地区名称)。此外,每个广告客户只能展示一个分类。这可能会这么难吗?

PPS:我试图尽可能地解决问题并最终得到这个问题:

SELECT cl.title
FROM classifieds cl
GROUP BY cl.advertiser_id
ORDER BY cl.timestamp DESC
LIMIT 5

令人难以置信的23秒!使用FORCE INDEX (advertiser_id)我可以将它带到1秒。如果我删除GROUP BY或ORDER BY,它会下降到0.0003秒。

我的表/索引有问题吗?我不应该FORCE INDEX(顺便说一句:USE INDEX不起作用 - 我需要强制它!)它不应该花那么长时间!

5 个答案:

答案 0 :(得分:3)

我不认为有任何办法可以避免排序168k行需要做的事情,无论索引如何。通过索引在表中查找行是一回事,但一旦找到它们,引擎仍然需要对它们进行排序。

1s对我来说似乎很合理。

(已删除编辑建议替代索引; OP尝试此操作但未成功)

答案 1 :(得分:2)

虽然稍作重组,但我会考虑在您的分类广告表上查看您的where子句,看看是否有任何索引可供使用......例如确认,价格,国家/地区。无论哪个可用的最低可能记录数我先列出 - 可能先把国家放在首位,然后再确认。 Addiitonally,删除组。您没有与查询关联的聚合函数。

SELECT STRAIGHT_JOIN
      cl.title, 
      cl.URL, 
      cl.ID AS ad_id, 
      cl.cat_id, 
      cl.price, 
      cs.name AS cat_name, 
      pix.file_name, 
      area.area_name  
   FROM 
      ( select clMax.advertiser_id, 
               max( clMax.TimeStamp ) as AdvMaxTime
           from findix.classifieds clMax
           where  clMax.confirmed = 1 
              AND clMax.price != '' 
              AND clMax.country = 'de'  
           group by 1
           order by 2 desc
           limit 5 ) clQualified,
      findix.classifieds cl,
      findix.classifieds_pix pix,
      findix.cat_names_sub cs,
      findix.zip_codes zip,
      findix.area_names area
   WHERE
          clQualified.advertiser_id = cl.advertiser_id
      AND clQualified.AdvMaxTime = cl.timestamp;
      AND cl.ID = pix.classified_id  
      AND cl.cat_id = cs.ID 
      AND cl.zip_id = zip.zip_id  
      AND zip.area_id = area.id

通过更改以匹配您的资格,我将其移至内部预查询,该内部预查询获取符合条件的每个广告客户,获取最新的最大时间戳条目订单,并将限制为5作为查询的第一个“表格”为结果集。从那时起,我有5条记录加入到其他表中,这些记录在您遇到时几乎是瞬间完成的。

答案 2 :(得分:1)

您是否尝试过多指数?

像这样:

CREATE INDEX adv_tt ON classifieds ( advertiser_id , `timestamp` );

甚至这个:

CREATE INDEX adv_tt ON classifieds 
( confirmed , price , country , advertiser_id , `timestamp` );

PS:我不知道MySQL首先应用GROUP BY还是ORDER BY,如果它首先是ORDER BY,你必须更改INDEX中的列顺序(... timestamp,advertiser_id )

答案 3 :(得分:0)

您是否尝试更新表格中的统计信息?

答案 4 :(得分:0)

您的查询是F * ed up ..您有GROUP BY cl.advertiser_idORDER BY cl.timestamp DESC 时间戳不在Group BY这不应该被允许!

为什么你有一个Group BY! 拿出来。删除force index. 然后修复你的代码,使它没有任何重复,这不是什么组合。

编辑: 尝试

SELECT cl.title, cl.URL, cl.ID AS ad_id, cl.cat_id, cl.price, cl.timestamp
cs.name AS cat_name, pix.file_name, area.area_name 
FROM findix.classifieds cl 
INNER JOIN findix.classifieds_pix pix ON cl.ID = pix.classified_id 
INNER JOIN findix.cat_names_sub cs ON cl.cat_id = cs.ID 
INNER JOIN findix.zip_codes zip ON cl.zip_id = zip.zip_id 
INNER JOIN findix.area_names area ON zip.area_id = area.id 
WHERE cl.confirmed = 1 AND cl.price != '' AND cl.country = 'de' 
ORDER BY cl.timestamp DESC 

SELECT cl.advertiser_id,cl.title, cl.URL, cl.ID AS ad_id, cl.cat_id, cl.price, cl.timestamp
max(cs.name) AS cat_name, max(pix.file_name) as file_name, max(area.area_name) as area.area_name
FROM findix.classifieds cl 
INNER JOIN findix.classifieds_pix pix ON cl.ID = pix.classified_id 
INNER JOIN findix.cat_names_sub cs ON cl.cat_id = cs.ID 
INNER JOIN findix.zip_codes zip ON cl.zip_id = zip.zip_id 
INNER JOIN findix.area_names area ON zip.area_id = area.id 
WHERE cl.confirmed = 1 AND cl.price != '' AND cl.country = 'de' 
Group By cl.advertiser_id,cl.title, cl.URL, cl.ID AS ad_id, cl.cat_id, cl.price, cl.timestamp
ORDER BY cl.timestamp DESC