尽管存在索引,但对大型 SQL table 的排序查询速度很慢
Sorted queries on a large SQL table are slow despite an index exists
我有一个非常大的 SQL Table(超过 3 mio 行)comment_field_data。
CREATE TABLE `comment_field_data` (
`cid` int(10) unsigned NOT NULL,
`comment_type` varchar(32) CHARACTER SET ascii NOT NULL COMMENT 'The ID of the target entity.',
`langcode` varchar(12) CHARACTER SET ascii NOT NULL,
`status` tinyint(4) NOT NULL,
`uid` int(10) unsigned NOT NULL COMMENT 'The ID of the target entity.',
`pid` int(10) unsigned DEFAULT NULL COMMENT 'The ID of the target entity.',
`entity_id` int(10) unsigned DEFAULT NULL COMMENT 'The ID of the target entity.',
`subject` varchar(64) DEFAULT NULL,
`name` varchar(60) DEFAULT NULL,
`mail` varchar(254) DEFAULT NULL,
`homepage` varchar(255) DEFAULT NULL,
`hostname` varchar(128) DEFAULT NULL,
`created` int(11) NOT NULL,
`changed` int(11) DEFAULT NULL,
`thread` varchar(255) NOT NULL,
`entity_type` varchar(32) CHARACTER SET ascii NOT NULL,
`field_name` varchar(32) CHARACTER SET ascii NOT NULL,
`default_langcode` tinyint(4) NOT NULL,
PRIMARY KEY (`cid`,`langcode`),
KEY `comment__id__default_langcode__langcode` (`cid`,`default_langcode`,`langcode`),
KEY `comment_field__comment_type__target_id` (`comment_type`),
KEY `comment_field__uid__target_id` (`uid`),
KEY `comment_field__created` (`created`),
KEY `comment__status_comment_type` (`status`,`comment_type`,`cid`),
KEY `comment__status_pid` (`pid`,`status`),
KEY `comment__num_new` (`entity_id`,`entity_type`,`comment_type`,`status`,`created`,`cid`,`thread`(191)),
KEY `comment__entity_langcode` (`entity_id`,`entity_type`,`comment_type`,`default_langcode`)
)
类似
的查询
SELECT entity_id FROM comment_field_data ORDER BY created LIMIT 300
表现很差(几秒钟)- 并且
EXPLAIN SELECT entity_id FROM comment_field_data ORDER BY created LIMIT 300;
+------+-------------+--------------------+-------+---------------+------------------+---------+------+---------+-----------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+--------------------+-------+---------------+------------------+---------+------+---------+-----------------------------+
| 1 | SIMPLE | comment_field_data | index | NULL | comment__num_new | 848 | NULL | 3384043 | Using index; Using filesort |
+------+-------------+--------------------+-------+---------------+------------------+---------+------+---------+-----------------------------+
表明尽管创建的列已有索引,但仍使用了文件排序。我根本不是 SQL 专家,我不知道可以做些什么来改善这种行为。有人可以帮忙吗?
您应该尝试更改索引键:
ALTER TABLE comment_field_data
DROP KEY `comment_field__created`,
ADD KEY `comment_field__created` (`created`, `entity_id`) ;
为了“鼓励”MariaDB 使用这个新索引,您可以像这样更改您的查询:
SELECT entity_id
FROM comment_field_data
WHERE created > '1970-01-01'
AND entity_id > 0
ORDER BY created LIMIT 300
希望这会有所帮助
这种技术被命名为索引覆盖,这意味着索引结构包含查询中调用的所有列。
使用这个索引,为了执行你的查询,MariaDB 将不必做额外的I/Os读取主键中包含的数据层。
我有一个非常大的 SQL Table(超过 3 mio 行)comment_field_data。
CREATE TABLE `comment_field_data` (
`cid` int(10) unsigned NOT NULL,
`comment_type` varchar(32) CHARACTER SET ascii NOT NULL COMMENT 'The ID of the target entity.',
`langcode` varchar(12) CHARACTER SET ascii NOT NULL,
`status` tinyint(4) NOT NULL,
`uid` int(10) unsigned NOT NULL COMMENT 'The ID of the target entity.',
`pid` int(10) unsigned DEFAULT NULL COMMENT 'The ID of the target entity.',
`entity_id` int(10) unsigned DEFAULT NULL COMMENT 'The ID of the target entity.',
`subject` varchar(64) DEFAULT NULL,
`name` varchar(60) DEFAULT NULL,
`mail` varchar(254) DEFAULT NULL,
`homepage` varchar(255) DEFAULT NULL,
`hostname` varchar(128) DEFAULT NULL,
`created` int(11) NOT NULL,
`changed` int(11) DEFAULT NULL,
`thread` varchar(255) NOT NULL,
`entity_type` varchar(32) CHARACTER SET ascii NOT NULL,
`field_name` varchar(32) CHARACTER SET ascii NOT NULL,
`default_langcode` tinyint(4) NOT NULL,
PRIMARY KEY (`cid`,`langcode`),
KEY `comment__id__default_langcode__langcode` (`cid`,`default_langcode`,`langcode`),
KEY `comment_field__comment_type__target_id` (`comment_type`),
KEY `comment_field__uid__target_id` (`uid`),
KEY `comment_field__created` (`created`),
KEY `comment__status_comment_type` (`status`,`comment_type`,`cid`),
KEY `comment__status_pid` (`pid`,`status`),
KEY `comment__num_new` (`entity_id`,`entity_type`,`comment_type`,`status`,`created`,`cid`,`thread`(191)),
KEY `comment__entity_langcode` (`entity_id`,`entity_type`,`comment_type`,`default_langcode`)
)
类似
的查询SELECT entity_id FROM comment_field_data ORDER BY created LIMIT 300
表现很差(几秒钟)- 并且
EXPLAIN SELECT entity_id FROM comment_field_data ORDER BY created LIMIT 300;
+------+-------------+--------------------+-------+---------------+------------------+---------+------+---------+-----------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+--------------------+-------+---------------+------------------+---------+------+---------+-----------------------------+
| 1 | SIMPLE | comment_field_data | index | NULL | comment__num_new | 848 | NULL | 3384043 | Using index; Using filesort |
+------+-------------+--------------------+-------+---------------+------------------+---------+------+---------+-----------------------------+
表明尽管创建的列已有索引,但仍使用了文件排序。我根本不是 SQL 专家,我不知道可以做些什么来改善这种行为。有人可以帮忙吗?
您应该尝试更改索引键:
ALTER TABLE comment_field_data
DROP KEY `comment_field__created`,
ADD KEY `comment_field__created` (`created`, `entity_id`) ;
为了“鼓励”MariaDB 使用这个新索引,您可以像这样更改您的查询:
SELECT entity_id
FROM comment_field_data
WHERE created > '1970-01-01'
AND entity_id > 0
ORDER BY created LIMIT 300
希望这会有所帮助
这种技术被命名为索引覆盖,这意味着索引结构包含查询中调用的所有列。
使用这个索引,为了执行你的查询,MariaDB 将不必做额外的I/Os读取主键中包含的数据层。