Database Mysql慢速查询:JOIN+;多个位置+;订购人
长时间潜伏者,第一个问题 我正在努力优化此查询,该查询选择与所选过滤器匹配的最低价项目:Database Mysql慢速查询:JOIN+;多个位置+;订购人,database,mysql,indexing,query-optimization,Database,Mysql,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
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
其解释是:
| 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 | |
| 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 |
及其解释:
| 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 | |
| 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 |
以下是表格:
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 ;
我的问题:-哪种查询结构似乎是最佳的?
-哪些索引将优化此查询?
-不太重要的是:当添加或删除WHERE子句或使用不同的排序方式(如按%off排序)时,索引方法如何改变:
ORDER BY (1-(MIN(product_all.sale_price)/product_info.retail_price)) DESC
编辑:两个查询的自然连接作用于prod\u id(product\u info中的一条记录可以在product\u all中有多个实例,这就是它们需要分组的原因)索引在mysql中起着巨大的作用,一个查询用了15分钟的时间,而一组错误的索引用了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
这里的性能增益是通过索引where子句中加入的主要字段而获得的。就个人而言,我会同意你的第一个问题,因为当你考虑它时,它应该表现得更好
据我所知,在第一个和第二个查询中发生了什么:
- 第一个查询正在被筛选 执行以下操作之前的子查询: 自然连接,这意味着它只有 加入结果数据,而不是 整张桌子
- 第二个查询是加入 整个第二张桌子,然后 筛选 一切都回到你想要的
编辑:我第一次错过了你的最后一个问题,答案是,如果你对主要连接字段进行索引,那么对where的更改只会对整体性能产生轻微影响,但是我在表上放置的唯一索引应该是你希望查询所基于的大部分内容。要记住的主要一点是,如果您经常查询或连接某个字段,那么它确实应该被索引,但是您不必担心在重新调整索引策略方面的小查询和对顺序的更改。就性能而言,使用它从来都不是一件好事
select *
您应该改用单独的列名
select column1,column2 etc...
就我个人而言,我是一个sql极简主义者,避免任何不能索引到索引列的子查询或联接 如果这真的不可能,我可能会单独运行子查询来收集密钥,在客户端站点对它们进行排序,然后构建where in(…)子句 JohnVD提出了很多好的观点,但如果您需要制作一个包含产品名称的唯一键,那么您应该真正了解它是否可以规范化为一个it 如果可能的话,要不惜一切代价避免索引varchar列。每个索引项都与列的最大大小一样大,即使它们通常只是列的一小部分。如果使用utf-8这样的字符集,那么大小是~maxlen+3
由于你方的限制,似乎需要订货。但是,作为一个参考,当你做分组时,如果你要使用整个结果集,那么就加上一个空的订单。通过explain运行这两个变体,了解原因;ORDERBYNULL消除了隐含的filesort,您可以在客户端对其进行排序。(如果您使用rollup执行group by,这是不可能的)您应该坚持第二个查询。对列使用索引,以最大程度地减少受影响的行。在这种情况下,可能是日期。如果筛选条件始终包含多个列,则应尝试使用多列索引。MySQL将只使用一个索引。正如米奇所说,试图找到自然具有较低记录数的标准肯定会赢得性能。如果Category+Gender非常常见,那么将其作为两列的索引。此外,一旦找到了最佳条件,您可以修改以下查询以更好地匹配它。“STRAIGHT_JOIN”告诉MySQL按照您声明的顺序进行操作,而不是试图更改用于查询basis和连接到其他数据库的主表。。。所以,我不知道哪一个更准确的分类索引、性别索引或日期索引。。。如果Date的记录基础更少,那么我会将其作为FROM子句中的第一个表进行交换,并在心里将其关于Date的标准移动到WHERE子句的第一个位置(只有我个人才能在视觉上与表保持同步)。我已经看到,在许多看似简单的查询的情况下,STRAIGHT_JOIN显著提高了性能
SELECT STRAIGHT_JOIN
product_info.*,
MIN(product_all.sale_price) as sale_price,
product_all.buy_link
FROM
product_info,
product_all
where
product_info.category = 2
AND product_info.gender = 'W'
and product_info.prod_id = product_all.prod_id
AND product_all.date = '2010-09-30'
GROUP BY
product_info.prod_id
ORDER BY
MIN(product_all.sale_price) ASC
LIMIT 13
其中一个PK是复合的,但每个组是一行:产品ID、该产品的最低价格和相关数据。编辑:这是对一条似乎已经消失的评论的回应。编辑2:是的,我想我点击了编辑而不是添加评论…很流畅。这是我知道的为数不多的事情之一,但我认为这可以忽略不计,并且可以提高我问题的可读性。乔恩,谢谢!这些多列索引起到了作用,而且您的编辑也很准确,order by并没有真正地向下拖动查询,因为它只对13行进行操作。干杯乔恩,你帮了我们大忙。上面的那个