chr*_*nch 7 mysql database indexing query-optimization
长时间潜伏,第一个问题!
我正在努力优化此查询,该查询选择与所选过滤器匹配的价格最低的商品:
SELECT product_info.*, MIN(product_all.sale_price) as sale_price, product_all.buy_link
FROM product_info
NATURAL JOIN (SELECT * FROM product_all WHERE product_all.date = '2010-09-30') as product_all
WHERE (product_info.category = 2
AND product_info.gender = 'W' )
GROUP BY product_all.prod_id
ORDER BY MIN(product_all.sale_price) ASC LIMIT 13
Run Code Online (Sandbox Code Playgroud)
它解释说:
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| 1 | PRIMARY | <derived2> | ALL | NULL | NULL | NULL | NULL | 89801 | Using temporary; Using filesort |
| 1 | PRIMARY | product_info | eq_ref | PRIMARY,category_prod_id_retail_price,category_ret... | PRIMARY | 4 | product_all.prod_id | 1 | Using where |
| 2 | DERIVED | product_all | ref | date_2 | date_2 | 3 | | 144107 | |
Run Code Online (Sandbox Code Playgroud)
我已经尝试消除子查询,直觉看起来更好但实际上需要更长时间:
SELECT product_info.*, MIN(product_all.sale_price) as sale_price, product_all.buy_link
FROM product_info
NATURAL JOIN product_all
WHERE (product_all.date = '2010-09-30'
AND product_info.category = 2
AND product_info.gender = 'W' )
GROUP BY product_all.prod_id
ORDER BY MIN(product_all.sale_price) ASC LIMIT 13
Run Code Online (Sandbox Code Playgroud)
它的解释是:
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| 1 | SIMPLE | product_info | ref | PRIMARY,category_prod_id_retail_price,category_ret... | category_retail_price | 5 | const | 269 | Using where; Using temporary; Using filesort |
| 1 | SIMPLE | product_all | ref | PRIMARY,prod_id,date_2 | prod_id | 4 | equipster_db.product_info.prod_id | 141 | Using where |
Run Code Online (Sandbox Code Playgroud)
以下是表格:
CREATE TABLE `product_all` (
`prod_id` INT( 10 ) NOT NULL PRIMARY KEY ,
`ref_id` INT( 10) NOT NULL PRIMARY KEY ,
`date` DATE NOT NULL ,
`buy_link` BLOB NOT NULL ,
`sale_price` FLOAT NOT NULL
) ENGINE = MYISAM ;
CREATE TABLE `product_info` (
`prod_id` INT( 10 ) NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`prod_name` VARCHAR( 200 ) NOT NULL,
`brand` VARCHAR( 50 ) NOT NULL,
`retail_price` FLOAT NOT NULL
`category` INT( 3 ) NOT NULL,
`gender` VARCHAR( 1 ) NOT NULL,
`type` VARCHAR( 10 ) NOT NULL
) ENGINE = MYISAM ;
Run Code Online (Sandbox Code Playgroud)
我的问题:
- 哪种查询结构似乎是最优的?
什么索引会优化这个查询?
- 重要的是:在添加或删除WHERE子句或使用不同的ORDER BY时,索引方法如何更改,例如按%off排序:
ORDER BY (1-(MIN(product_all.sale_price)/product_info.retail_price)) DESC
Run Code Online (Sandbox Code Playgroud)
编辑:两个查询的自然连接作用于prod_id(product_info中的一条记录可以在product_all中有多个实例,这就是为什么需要对它们进行分组)
索引在 mysql 中产生了巨大的差异,一个查询需要 15 分钟,如果使用一组错误的索引,则需要 0.2 秒,而使用正确的索引则需要 0.2 秒,但找到正确的平衡通常是问题所在。当然,如果没有一些示例数据,很难说下面的解决方案是否会节省您的时间,但理论上它应该可以。
为了回答您的问题,我将重新设计表格,如下所示:
CREATE TABLE `product_all` (
`prod_id` INT( 10 ) NOT NULL,
`ref_id` INT( 10) NOT NULL,
`date` DATE NOT NULL ,
`buy_link` BLOB NOT NULL ,
`sale_price` FLOAT NOT NULL,
PRIMARY KEY (prod_id, ref_id) ,
INDEX date_Index (`date` ASC),
UNIQUE INDEX prod_price_Index (prod_id ASC, sale_price ASC)
) ENGINE = MYISAM ;
CREATE TABLE `product_info` (
`prod_id` INT( 10 ) NOT NULL AUTO_INCREMENT,
`prod_name` VARCHAR( 200 ) NOT NULL,
`brand` VARCHAR( 50 ) NOT NULL,
`retail_price` FLOAT NOT NULL,
`category` INT( 3 ) NOT NULL,
`gender` VARCHAR( 1 ) NOT NULL,
`type` VARCHAR( 10 ) NOT NULL,
PRIMARY KEY (prod_id) ,
UNIQUE INDEX prod_id_name_Index (prod_id ASC, prod_name ASC),
INDEX category_Index (category ASC),
INDEX gender_Index (gender ASC)
) ENGINE = MYISAM ;
SELECT product_info.*, MIN(product_all.sale_price) as sale_price, product_all.buy_link
FROM product_info
NATURAL JOIN (SELECT * FROM product_all WHERE product_all.date = '2010-09-30') as product_all
WHERE (product_info.category = 2
AND product_info.gender = 'W' )
GROUP BY product_all.prod_id
ORDER BY MIN(product_all.sale_price) ASC LIMIT 13
Run Code Online (Sandbox Code Playgroud)
这里的性能提升是通过对正在连接的主要字段建立索引并在 where 子句中获得的。就我个人而言,我会选择您的第一个查询,因为当您认为它应该表现得更好时。
据我了解第一个和第二个查询中发生的情况:
根据经验,通常您希望在主要连接字段以及 where 子句中最常使用的字段上添加索引。我还在您想要定期查询的一些字段上放置了一些唯一索引,例如 prod_id_name_Index。
如果这不能提高您的性能,如果您可以发布一些虚拟数据来使用,我也许可以获得一个可以进行基准测试的更快的解决方案。
这是一篇介绍 mysql 索引性能的文章,如果您想了解更多信息,值得一读。
祝你好运!
编辑:我第一次错过了你的最后一个问题,答案是,如果你对主要连接字段建立索引,然后更改为 where 只会稍微影响整体性能,但我放在表上的唯一索引应该考虑到您想要查询的大部分内容。要记住的主要事情是,如果您频繁查询或连接某个字段,那么它确实应该被索引,但是您不应该担心重新调整索引策略方面的小查询和顺序更改。