如何优化 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 有更多变化。
关于查询的一些说明:
- availability='1' 应该是 availability=1 以避免不必要的 int->varchar 转换。
- "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 BY
和 ORDER BY
之间的不匹配阻止利用 LIMIT
。
这个
INDEX(product, availability, store, brand, id)
将是 "covering" 并且顺序正确。但请注意,我已经交换了 store
和 brand
...
将查询更改为
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)
。
此查询的正确索引是什么。
我尝试为此查询提供不同的索引组合,但它仍在使用临时文件、文件排序等。
总计 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 有更多变化。
关于查询的一些说明:
- availability='1' 应该是 availability=1 以避免不必要的 int->varchar 转换。
- "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 BY
和 ORDER BY
之间的不匹配阻止利用 LIMIT
。
这个
INDEX(product, availability, store, brand, id)
将是 "covering" 并且顺序正确。但请注意,我已经交换了 store
和 brand
...
将查询更改为
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)
。