如何优化 MYSQL in Extra :-Using where;使用临时的;使用文件排序

How to Optimize MYSQL in Extra :-Using where; Using temporary; Using filesort

此查询的正确索引是什么。

我尝试为此查询提供不同的索引组合,但它仍在使用临时文件、文件排序等。

总计 table 数据 - 7,60,346

product= 'Dresses' - 总行数 = 122 554

CREATE TABLE IF NOT EXISTS `product_data` (
  `table_id` int(11) NOT NULL AUTO_INCREMENT,
  `id` int(11) NOT NULL,
  `price` int(11) NOT NULL,
  `store` varchar(255) NOT NULL,
  `brand` varchar(255) DEFAULT NULL,
  `product` varchar(255) NOT NULL,
  `model` varchar(255) NOT NULL,
  `size` varchar(50) NOT NULL,
  `discount` varchar(255) NOT NULL,
  `gender_id` int(11) NOT NULL,
  `availability` int(11) NOT NULL,
  PRIMARY KEY (`table_id`),
  UNIQUE KEY `table_id` (`table_id`),
  KEY `id` (`id`),
  KEY `discount` (`discount`),
  KEY `step_one` (`product`,`availability`),
  KEY `step_two` (`product`,`availability`,`brand`,`store`),
  KEY `step_three` (`product`,`availability`,`brand`,`store`,`id`),
  KEY `step_four` (`brand`,`store`),
  KEY `step_five` (`brand`,`store`,`id`)
) ENGINE=InnoDB ;

查询:

SELECT id ,store,brand FROM `product_data` WHERE product='dresses' and 
availability='1' group by brand,store order by store limit 10;

excu..time :- (10 total, Query took 1.0941 sec)

解释计划:


possible_keys :- step_one, step_two, step_three, step_four, step_five

关键:- step_two

ref :- const,const

行:- 229438

额外:-使用哪里;使用临时的;使用文件排序

我试过这些索引


Key step_one (product,availability)

Key step_two (product,availability,brand,store)

Key step_three (product,availability,brand,store,id)

Key step_four (brand,store)

Key step_five (brand,store,id)

对于索引,最好的索引是step_two。 product 字段用于 where 并且比 availability-field 有更多变化。

关于查询的一些说明:

  1. availability='1' 应该是 availability=1 以避免不必要的 int->varchar 转换。
  2. "group by brand" 不应使用,因为 GROUP BY 仅应在您将聚合函数用作选定列时使用。你想通过 group by 达到什么目的?

如果没有聚合函数,您的 group by clause 就没有任何意义。

如果您可以将查询重写为

SELECT id ,store 
FROM `product_data` 
WHERE product='dresses' 
and availability='1' 
order by store limit 10;

然后 (product,availability,store) 上的索引将删除所有文件排序。

参见 SQLFiddle:http://sqlfiddle.com/#!9/60f33d/2

更新:

SQLFiddle 使您的意图明确 - 您正在使用 GROUP BY 来模拟 DISTINCT。如果是这种情况,我认为您无法摆脱查询中的文件排序和临时 table 步骤 - 但我也不认为这些步骤应该非常昂贵。

真正的问题不是索引,而是 GROUP BYORDER BY 之间的不匹配阻止利用 LIMIT

这个

INDEX(product, availability, store, brand, id)

将是 "covering" 并且顺序正确。但请注意,我已经交换了 storebrand...

将查询更改为

SELECT  id ,store,brand
    FROM  `product_data`
    WHERE  product='dresses'
      and  availability='1'
    GROUP BY store, brand    -- change
    ORDER BY store, brand    -- change
    limit  10;

这会将 GROUP BY 更改为以 store 开头,以反映 ORDER BY 排序 - 这避免了额外的排序。并将 ORDER BY 更改为与 GROUP BY 相同,以便可以将两者组合。

考虑到这些变化,INDEX 现在可以一直到 LIMIT,从而允许处理只查看 10 行,而不是更大的集合。

任何少于所有这些变化的东西都不会那么有效。

进一步讨论:

INDEX(product, availability,   -- these two can be in either order
      store, brand,      -- must match both `GROUP BY` and `ORDER BY`
      id)   -- tacked on (on the end) to make it "covering"

"Covering" 表示 所有 SELECT 的列都在 INDEX 中找到,因此无需进入数据.

但是... 整个查询没有意义 因为 id 包含在 SELECT 中。如果您想查找哪些商店有可用的连衣裙,请去掉 id。如果你想列出所有可用的衣服,然后将 id 更改为 GROUP_CONCAT(id)