按日期排序始终使用文件排序。

huangapple go评论57阅读模式
英文:

Order by date always uses filesort

问题

以下是您要的代码部分的中文翻译:

CREATE TABLE `test` (
	`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
	`number` INT(10) UNSIGNED NOT NULL,
	`revision` INT(10) UNSIGNED NOT NULL,
	`autosave` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0',
	`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
	`blob` LONGBLOB NOT NULL,
	PRIMARY KEY (`id`) USING BTREE,
	UNIQUE INDEX `number_revision_autosave` (`number`, `revision`, `autosave`) USING BTREE,

    -- 以下部分原始表定义中没有,但是我尝试解决自己的问题
	UNIQUE INDEX `number_revision_autosave_created_at` (`number`, `revision`, `autosave`, `created_at`) USING BTREE 
);

Blob列可能会相对较大。平均约为20kb,但可能更大(没有真正的上限,但可以假定有一个实际上的上限为20-30mb)。

当我使用以下查询时:

SELECT *
FROM test
WHERE `number` = 1 
 	AND autosave=0
ORDER BY `revision` DESC

一切都运行良好。

然而,如果我使用以下查询:

SELECT *
FROM test

-- 这也是我的尝试解决的一部分
USE INDEX (number_revision_autosave_created_at)

WHERE `number` = 1 
 	AND autosave=0
ORDER BY `created_at` DESC

有时会出现“错误1038,内存不足,请考虑增加服务器排序缓冲区大小”。

在经过一番研究后,可以注意到第一个查询的解释中显示了“使用where;反向索引扫描”在额外信息中,而第二个查询则显示了“使用索引条件;使用文件排序”。

在这一点上,“内存不足错误”开始变得更有意义,因为我的排序缓冲区大小为256kb,而结果集包含了大于此的单个行。

为了解决这个问题,我创建了一个包括created_at的索引,即:

UNIQUE INDEX `number_revision_autosave_created_at` (`number`, `revision`, `autosave`, `created_at`) USING BTREE

然后尝试通过执行USE INDEX (number_revision_autosave_created_at)来“说服”MySQL使用此索引,然而,尽管MySQL实际上使用了这个索引,但它仍然选择执行文件排序。

目前,我已经将排序缓冲区大小增加到约30mb,以覆盖这些极端情况,但这不是一个理想的(或未来可行的)解决方案。

我不确定我可以做什么来使它像前一种情况一样使用索引扫描。问题出在哪里?默认的表引擎是InnoDB,我正在使用MySQL Community版本8.0.32。

英文:

I have the following table definition:

CREATE TABLE `test` (
	`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
	`number` INT(10) UNSIGNED NOT NULL,
	`revision` INT(10) UNSIGNED NOT NULL,
	`autosave` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0',
	`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
	`blob` LONGBLOB NOT NULL,
	PRIMARY KEY (`id`) USING BTREE,
	UNIQUE INDEX `number_revision_autosave` (`number`, `revision`, `autosave`) USING BTREE,

    -- The following was not there originally but my attempt to solve my own issue
	UNIQUE INDEX `number_revision_autosave_created_at` (`number`, `revision`, `autosave`, `created_at`) USING BTREE 
);

the blob column can potentially be large(ish). On average it's about 20kb but can be much larger (there's no real upper limit, but a practical limit of 20-30mb can be assumed).

When I use a query like this:

select *
from test
WHERE `number` = 1 
 	AND autosave=0
order by `revision` desc

everything is working great

However if I use:

select *
from test

-- This is also my attempt at a solution
USE INDEX (number_revision_autosave_created_at)

WHERE `number` = 1 
 	AND autosave=0
order by `created_at` desc

I sometimes get Error "1038 Out of sort memory, consider increasing server sort buffer size

After a bit of looking into it the notable difference is that the explain of the 1st query is showing: Using where; Backward index scan in the extras while the second one is showing Using index condition; Using filesort

The "out of sort memory error" started making more sense at this point because my sort buffer size was 256kb and the result set contained single rows that were larger than this.

In my attempt to solve this I created an index which included created_at i.e.

UNIQUE INDEX `number_revision_autosave_created_at` (`number`, `revision`, `autosave`, `created_at`) USING BTREE 

Then tried to "persuade" MySQL to use that one by doing USE INDEX (number_revision_autosave_created_at) however, while MySQL did actually use this index, it still opted to do a filesort.

For now I have increased to sort buffer size to about 30mb, to cover these edge cases, but this is not an ideal (or future proof) solution.

I am not sure what I can do to make it use an index scan like in the previous case. What is the problem here? Default table engine is InnoDB and I am using MySQL Community version 8.0.32

答案1

得分: 2

索引中列的顺序很重要,因为MySQL只能依次从左边的列开始使用列。

您的索引在左起第2个位置包括revision列,但该列在左起第2个位置的where子句中没有包括。这意味着您的索引只能用于样本查询以筛选number列。

为了加速您的问题中的查询,请添加一个具有以下列顺序的索引:number - autosave - created_at

英文:

The order of columns in an index matters as mysql can only proced to use columns starting from left one after the other.

Your indexes include revision column at the 2nd position from left, but this column is not included in the where clause at the 2nd position. This means, your indexes can only be used by the sample queries to filter on the number column.

Ad an index with this exact order of columns to speed the queries up in your question: number - autosave - created_at

huangapple
  • 本文由 发表于 2023年3月3日 18:46:49
  • 转载请务必保留本文链接:https://go.coder-hub.com/75626069.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定