我在一张包含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
查询不太熟悉。我在这里找不到什么东西?
答案 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的索引?! (这取决于您使用该条目查询的频率)