提高 MySQL 查询性能 - 可能的索引问题

Posted

技术标签:

【中文标题】提高 MySQL 查询性能 - 可能的索引问题【英文标题】:Improving MySQL query performance - possible index problems 【发布时间】:2015-02-09 10:47:25 【问题描述】:

我见过很多类似我的问题,但在阅读完所有问题后,我感到很困惑。

总而言之 - 我有一个查询,它从表中选择产品并从其他表中添加有关它们的更多信息。

查询:

SELECT 
      p.product_id, 
      p.product_name, 
      p.product_seo_url, 
      p.product_second_name, 
      p.product_intro_plain, 
      p.product_price,
      p.product_price_promo, 
      p.product_promo_expire_date, 
      p.product_views,
      p.product_code, 
      p.product_exquisite, 
      p.product_rating, 
      p.product_votes,
      p.product_date_added, 
      p.product_returned, 
      p.product_price_returned,
      ( SELECT gal.image_filelocation 
           FROM 3w_products_gallery gal 
           WHERE gal.product_id = p.product_id 
           ORDER BY show_order ASC 
           LIMIT 1 )  image_filelocation, 
      m.man_image_location, 
      m.man_name, 
      m.man_seo_url 
   FROM 
      3w_products p 
         LEFT JOIN 3w_manufacturers m 
            ON p.man_id = m.man_id
         LEFT JOIN 3w_products_cat_rel pcr 
            ON p.product_id  = pcr.product_id
   WHERE 
          pcr.ctg_id = '19'
      AND p.man_id = '190'
   ORDER BY 
      p.product_id DESC 
   LIMIT 
      0, 24

发生的奇怪事情是查询有时会执行 0.001 秒。有时持续 30 多秒。

EXPLAIN 显示的是: http://i.stack.imgur.com/ZNtBX.png

我认为问题在于表的索引。你能告诉我如何设置它们吗?

如果您需要有关表格或其他任何信息的更多信息,请告诉我!

最好, 迪米塔

【问题讨论】:

你知道 "WHERE (pcr.ctg_id = '19')" 使 pcr 外连接作为内连接执行吗? (如果您真的想要左连接,请将条件移动到左连接的 ON 子句。) 你在ASC LIMIT 1) image_filelocation,附近漏了一个逗号括号内的查询结束后应该有一个逗号 这两者之间应该有“as”。 如果在没有最后一个LIMIT 的情况下运行,查询预计返回多少行?在这里,指令ORDER BY DESC LIMIT 只能在整个工作完成后进行评估。我猜有些 ctg_id/man_id 部分相当大。 @user4419802 - 大约 1000 个结果。 【参考方案1】:

如果您的“ID”列实际上是数字,请删除它们周围的暗示字符串的引号......即使它会隐含转换。如果是数字,请保持数字。

正如 cmets 中的另一个所说,您通过“pcr”别名的左连接及其在 WHERE 子句中的条件将其转换为内连接。

 FROM 
      3w_products p 
         LEFT JOIN 3w_manufacturers m 
            ON p.man_id = m.man_id
         LEFT JOIN 3w_products_cat_rel pcr 
            ON p.product_id  = pcr.product_id
            AND pcr.ctg_id = 19
   WHERE 
      AND p.man_id = 190

字段级查询可能会降低性能,因为每个字段(您的图像位置)的选择对每条记录都执行一次。为了至少有助于提高性能,表 3w_products_gallery 应该有一个索引 ON (product_id, show_order)

您的 3w_products 主表应该有一个关于 (man_id, product_id) 的索引... Man_ID 用于按制造商优化 WHERE 子句,还有产品 ID 以帮助优化 ORDER BY 标准。

您的 3w_manufacturers 表,我怀疑 (man_id) 上已经有一个有效索引,因为它似乎是该表的主键。

此外,作为基于网络的内容,您最好通过为“GalleryShowOrder”添加一个新列来对产品表进行去规范化。然后,向您的 Gallery 表添加一个触发器,任何插入或更新都会将第一个“showOrder”值推回产品表。这样,当您查询时,您只需在产品上的该表中添加另一个联接并知道显示订单。如果您的画廊返回 1000 条记录,即使您只限制为 24 条,它仍然需要在应用 order by 之前获取所有记录。因此,每个图库图像都有 1000 个子查询。

你的字段选择会变成

gal.image_filelocation, 

您的 JOIN 将添加以下内容

  LEFT JOIN 3w_products_gallery gal 
     on p.product_id = gal.product_id
    AND p.GalleryShowOrder = gal.show_order

【讨论】:

'table 3w_products_gallery 应该有一个索引 ON (product_id, show_order)' - 好吧,它只有在给定 id 有一堆图像时才有用。否则,纯 index ON (product_id) 就足够了。 'main 3w_products table 应该在 (man_id, product_id )' 上有一个索引 - 同样,如果 TS 声明查询返回不超过 1000 行,则使用复合优化 ORDER BY 是没有用的指数。另请考虑,mysql 可能无法优化ORDER BY DESC,因为它需要不支持的index ON (man_id, product_id DESC)(请参阅use-the-index-luke.com/sql/sorting-grouping/…)

以上是关于提高 MySQL 查询性能 - 可能的索引问题的主要内容,如果未能解决你的问题,请参考以下文章

高性能MySQL之索引深入原理分析

高性能MySQL之索引深入原理分析

44 mysql索引

30分钟帮助你提高mysql性能设计

30分钟帮助你提高mysql性能设计

mysql性能优化-自我总结