Mysql-为什么文件排序比实际获取时间长?
我在Mysql数据库上运行了一个sql查询。 我有一张有150万张唱片的桌子。我正在尝试获取最后50个创建的项目,基于项目的创建者 以下是查询:Mysql-为什么文件排序比实际获取时间长?,mysql,database-performance,Mysql,Database Performance,我在Mysql数据库上运行了一个sql查询。 我有一张有150万张唱片的桌子。我正在尝试获取最后50个创建的项目,基于项目的创建者 以下是查询: SELECT * FROM `items` WHERE `items`.`owner_id` IN (1, 2, 3, 4, 5, 6, 7, 8) ORDER BY `items`.`id` DESC LIMIT 50 查询使用的是owner\u id索引,这很有意义。正确的? 显然,使用这个索引几乎需要3秒钟,而使用主索引则需要100毫秒
SELECT *
FROM `items`
WHERE `items`.`owner_id`
IN (1, 2, 3, 4, 5, 6, 7, 8)
ORDER BY `items`.`id`
DESC LIMIT 50
查询使用的是owner\u id索引,这很有意义。正确的?
显然,使用这个索引几乎需要3秒钟,而使用主索引则需要100毫秒
在运行explain时,我看到以下内容:
1 SIMPLE items range idx_owner idx_owner 4 NULL 56 Using index condition; Using filesort
但是,当我运行以下查询时:
SELECT *
FROM `items` FORCE INDEX(PRIMARY)
WHERE `items`.`owner_id`
IN (1, 2, 3, 4, 5, 6, 7, 8)
ORDER BY `items`.`id`
DESC LIMIT 50
我得到以下解释:
1 SIMPLE items index NULL PRIMARY 4 NULL 50 Using where
这意味着我刚刚摆脱了filesort,尽管我丢失了where子句的索引
该查询似乎返回15000条记录(由于in),然后对它们进行排序并选择最后50条。
至于我的问题——为什么对15000条记录进行排序比扫描150万张表并搜索15000条记录的效率要低?排序不应该是一项如此困难的任务,而搜索要困难得多(没有索引!)我遗漏了什么
附件-表格索引:
items 0 PRIMARY 1 id A 1444298 NULL NULL BTREE
items 1 items_a951d5d6 1 slug A 288859 767 NULL BTREE
items 1 category_id_refs_id_3b77a81e 1 category_id A 34 NULL NULL YES BTREE
items 1 origin_id_refs_id_99b3fd12 1 origin_id A 2 NULL NULL YES BTREE
items 1 parent_id_refs_id_99b3fd12 1 parent_id A 6 NULL NULL YES BTREE
items 1 name 1 name A 1444298 NULL NULL BTREE
items 1 idx_owner 1 owner_id A 722149 NULL NULL BTREE
谢谢 对数千行完整信息进行排序并不像您想象的那么便宜。另外,请注意,
filesort
并不一定意味着对文件系统中的文件进行排序。这意味着需要对派生表进行排序
您正在查看的查询可以进行如下重构,结果很可能会更好
SELECT i.*
FROM items AS i
JOIN (
SELECT id
FROM items
WHERE owner_id IN (1, 2, 3, 4, 5, 6, 7, 8)
ORDER BY id DESC
LIMIT 50
) AS j ON i.id = j.id
ORDER BY i.id DESC
这是因为原始查询包含SELECT*
。为了满足这个查询,MySQL必须洗牌表中的所有列。此重构中的子查询只提供了所需的50个id
值。它仍然需要对它们进行排序,但是排序一组整数比排序一组行要快
SELECT id
FROM items
WHERE owner_id IN (1, 2, 3, 4, 5, 6, 7, 8)
ORDER BY id DESC
LIMIT 50
外部查询为这50个ID中的每一个检索整行,这应该相对较快
这里有一些值得注意的地方
WHERE owner_id BETWEEN 1 AND 8
MySQL将比
WHERE owner_id IN (1, 2, 3, 4, 5, 6, 7, 8)
因为服务器可以对owner\u id
上的索引执行单个范围扫描。您可能无法在所有情况下都在之间使用,但如果可以,请使用
如果此查询对性能至关重要,则可以尝试在上创建复合索引
(owner_id, id)
看看它是否能大大加快查询速度。MySQL仍然使用中的进行范围扫描,EXPLAIN
结果证明了这一点。此外,除了覆盖索引之外,(owner\u id,id)
上的多列索引也不会有帮助,除非搜索只针对一个owner\u id。不过,这是一个不错的答案。如果MySQL足够聪明(非常了解我们的数据),能够自己进行这些类型的优化(比如子查询)就好了。就在最后一个问题上,我的印象是排序只对row_id(这是一个整数字段)执行操作。为什么查询中的列数会影响排序的性能呢?排序必须对一个表进行排序——包括关键列和正在排序的其他列。表越小=排序越快。可以通过减少行数或列数使表变小。这里我的建议是将多行多列排序转换为多行一列排序。