我的Mysql数据库上运行了一个SQL查询。 我有一张1.5M记录的表格。我试图根据项目'来获取最后创建的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_id索引,这是有道理的。对? 显然,使用此索引需要将近3秒,而使用主索引需要100毫秒。
在完成解释时,我会看到以下内容:
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
这意味着我只是摆脱了文件排序,虽然我在where子句上丢失了索引。
查询似乎返回15,000条记录(由于输入),然后对它们进行排序并选择最后50条记录。 至于我的问题 - 如何排序15,000条记录的效率低于扫描1.5M表并搜索15,000条记录?排序不应该是一项艰巨的任务,而搜索则更困难(没有索引!)我错过了什么?
附加 - 表的索引:
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
谢谢!
答案 0 :(得分:2)
排序数千个完整的信息行并不像你想象的那么便宜。另请注意,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必须对表的所有列进行洗牌。此重构中的子查询只是提供了您想要的五十个id
值。它仍然需要对它们进行排序,但排序一堆整数比排序一堆行更快。
SELECT id
FROM items
WHERE owner_id IN (1, 2, 3, 4, 5, 6, 7, 8)
ORDER BY id DESC
LIMIT 50
外部查询检索这五十个ID中的每一个的整行,这应该相对较快。
这里需要注意的事情。
WHERE owner_id BETWEEN 1 AND 8
MySQL将比更容易满足
WHERE owner_id IN (1, 2, 3, 4, 5, 6, 7, 8)
因为服务器可以对owner_id
上的索引执行单一范围扫描。您可能无法在所有情况下使用BETWEEN
,但如果可以,请执行此操作。
如果此查询对性能至关重要,您可以尝试在
上创建复合索引(owner_id, id)
并查看它是否加快了查询速度。