在MySQL中出现意外缓慢的基本查询

时间:2018-01-04 17:06:25

标签: mysql database

我在一张包含189,000条记录的表格上运行基本选择。表结构是:

items

id - primary key
ad_count - int, indexed
company_id - varchar, indexed
timestamps

选择查询是:

select * 
from `items` 
where `company_id` is not null 
    and `ad_count` <= 100 
order by `ad_count` desc, `items`.`id` asc 
limit 50 

在我的生产服务器上,执行的MySQL部分需要300到400毫秒

如果我运行explain,我会:

select type: SIMPLE 
table: items    
type: range 
possible_keys: items_company_id_index,items_ad_count_index  
key: items_company_id_index 
key_len: 403    
ref: NULL   
rows: 94735 
Extra: Using index condition; Using where; Using filesort

在我们的应用程序中获取此数据时,我们将其分组为50,但上面的查询是&#34;第一页&#34;

我对解剖explain查询不太熟悉。我在这里找不到什么东西?

3 个答案:

答案 0 :(得分:1)

具有不同排序顺序的ORDER BY子句可能导致创建临时表和filesort。 MySQL(包括)v5.7下面的MySQL根本不能很好地处理这种情况,并且在ORDER BY子句中索引字段实际上没有意义,因为MySQL的优化器永远不会使用它们。 因此,如果应用程序的要求允许,最好对ORDER BY子句中的所有列使用相同的顺序。

所以在这种情况下:

order by `ad_count` desc, `items`.`id` asc

将成为:

order by `ad_count` desc, `items`.`id` desc
P.S,作为阅读更多信息的一个小技巧 - 似乎MySQL 8.0将会改变一些事情,这些用例在发布时可能表现得更好。

答案 1 :(得分:0)

尝试使用items_company_id_index上的多列索引替换(company_id, ad_count)

DROP INDEX items_company_id_index ON items;
CREATE INDEX items_company_id_ad_count_index ON items (company_id, ad_count);

这将允许它使用索引来测试WHERE子句中的两个条件。目前,它只使用索引查找非空company_id,然后对这些记录进行全面扫描以测试ad_count。如果大多数记录都具有非空company_id,则会扫描大部分表格。

您不需要仅在company_id列上保留旧索引,因为多列索引也是任何前缀列的索引,因为B树的工作方式。 / p>

答案 2 :(得分:0)

我可能在这里错了(取决于你的sql版本,这可能会更快)但是尝试使用公司表格进行内部联接。

像:

Select *
From items
INNER JOIN companies ON companies.id = items.company_id
 and items.ad_count <= 100
LIMIT 50;

由于你的索引计数很高,每次插入新条目时,btree都会减慢数据库的速度。也许删除ad_count的索引?! (这取决于您使用该条目查询的频率)