【问题标题】:Optimize mysql query: products <- N:N -> categories优化mysql查询:products <- N:N -> categories
【发布时间】:2014-01-26 03:36:36
【问题描述】:

有什么方法可以以更优化的方式进行此查询?

select SQL_NO_CACHE count(*) from products p
INNER JOIN `products_categories` AS `pc` ON p.id = pc.products_id
where pc.categories_id = 87

我的架构很简单:产品、类别和 N:N 连接表:products_categories。产品约400000行。 products_categories 大约是 600000。类别 = 87 的产品大约是 18000。使用 explain 给出:

id  select_type table   type    possible_keys   key key_len ref rows    Extra
1   SIMPLE  pc  index   products_id products_id 8   NULL    612469  Using where; Using index
1   SIMPLE  p   eq_ref  PRIMARY PRIMARY 4   stagingbagthis.pc.products_id   1   Using index

在我看来,rows = 612469 的第一行并不是一个好兆头。那么,可以以任何可能的方式优化此查询吗?

【问题讨论】:

    标签: mysql sql


    【解决方案1】:

    如果您删除了products 表会怎样:

    select SQL_NO_CACHE count(*)
    from products_categories` `pc` 
    where pc.categories_id = 87;
    

    为此,您需要products_categories(categories_id) 上的索引,或categories_id 是第一列的类似索引。

    【讨论】:

      【解决方案2】:

      您需要在products_categories.categories_id 上建立索引,以便优化WHERE 子句。

      【讨论】:

      • 我已经有一个索引(products_id, categories_id)。但是那个不是好东西?
      • 不,这无济于事。复合索引可用于优化索引的前缀,但categories_id 不是该索引的前缀。如果将其更改为(categories_id, products_id),它将起作用,但是只查找products_id 的查询会很慢。因此,您需要复合索引以及复合索引中第二列的单个索引。
      • 这个建议和@Gordon Linoff 都已实现,但主要改进是添加了索引。谢谢
      【解决方案3】:

      你可以试试这个。

      select SQL_NO_CACHE count(*) from products p
          INNER JOIN `products_categories` AS `pc` 
              ON p.id = pc.products_id and pc.categories_id = 87
      

      同时检查您的索引的基数,我们发现了基数不正常的情况,我们需要分析表以使我们的执行计划恢复一致。

      【讨论】:

      • 没有区别。在 INNER JOIN 中,您应该只具有与 ON 子句中的表相关的条件。单表条件等价于WHERE
      • 我在更复杂的查询中遇到过移动单表条件改变了执行计划的案例。
      猜你喜欢
      • 2011-01-22
      • 2011-07-07
      • 2018-12-21
      • 2010-12-15
      • 2011-11-04
      • 2016-01-25
      相关资源
      最近更新 更多