首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >mysql中密钥集分页的索引

mysql中密钥集分页的索引
EN

Stack Overflow用户
提问于 2019-07-26 16:25:03
回答 2查看 797关注 0票数 2

我试图在mysql中构建一个索引,以支持键集分页查询。我的查询如下:

代码语言:javascript
复制
SELECT * FROM invoice 
  WHERE company_id = 'someguid' 
    AND id > 'lastguidfromlastpage' 
  ORDER BY id
  LIMIT 10

这方面的常识是,company_id上的索引将包含表的主键(id)。因此,我希望能够直接使用索引中的行,而不需要查询首先排序结果,但是,我的解释计划显示了一个文件和一个索引合并:

代码语言:javascript
复制
mysql> explain SELECT *
-> FROM invoice
-> WHERE company_id = '37687714-2e9d-4daa-aee6-f7d56962f903'
->   AND id > '525ae038-0cc3-4f9a-85e6-6f36d43fae40'
-> ORDER BY id
-> LIMIT 10;
+----+-------------+---------+------------+-------------+-----------------------------+-----------------------------+---------+------+------+----------+---------------------------------------------------------------------------+
| id | select_type | table   | partitions | type        | possible_keys               | key                         | key_len | ref  | rows | filtered | Extra                                                                     |
+----+-------------+---------+------------+-------------+-----------------------------+-----------------------------+---------+------+------+----------+---------------------------------------------------------------------------+
|  1 | SIMPLE      | invoice | NULL       | index_merge | PRIMARY,invoice__company_id | invoice__company_id,PRIMARY | 76,38   | NULL |   48 |   100.00 | Using intersect(invoice__company_id,PRIMARY); Using where; Using filesort |
+----+-------------+---------+------------+-------------+-----------------------------+-----------------------------+---------+------+------+----------+---------------------------------------------------------------------------+
1 row in set, 1 warning (0.00 sec)

如果我显式地将id添加到索引中,那么我就得到了我期望的解释计划:

代码语言:javascript
复制
mysql> explain SELECT *
    -> FROM invoice
    -> WHERE company_id = '37687714-2e9d-4daa-aee6-f7d56962f903'
    ->   AND id > '525ae038-0cc3-4f9a-85e6-6f36d43fae40'
    -> ORDER BY id
    -> LIMIT 10;
+----+-------------+---------+------------+-------+--------------------------------+--------------------------------+---------+------+------+----------+-----------------------+
| id | select_type | table   | partitions | type  | possible_keys                  | key                            | key_len | ref  | rows | filtered | Extra                 |
+----+-------------+---------+------------+-------+--------------------------------+--------------------------------+---------+------+------+----------+-----------------------+
|  1 | SIMPLE      | invoice | NULL       | range | PRIMARY,invoice__company_id_id | invoice__company_id_id,PRIMARY | 76      | NULL |   98 |   100.00 | Using index condition |
+----+-------------+---------+------------+-------+--------------------------------+--------------------------------+---------+------+------+----------+-----------------------+
1 row in set, 1 warning (0.00 sec)

显示创建表:

代码语言:javascript
复制
CREATE TABLE `invoice` (
  `id` varchar(36) NOT NULL,
  `company_id` varchar(36) NOT NULL DEFAULT '0',
  `invoice_number` varchar(36) NOT NULL DEFAULT '0',
  `identifier` varchar(255) NOT NULL,
  `created_on` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `created_by` varchar(36) DEFAULT NULL,
  `data_source` varchar(36) NOT NULL,
  `type` varchar(45) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `invoice__company_id_id` (`company_id`,`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1

选择@@optimizer_switch;

代码语言:javascript
复制
use_index_extensions=on

MySQL版本:

  • 版本: 5.7.26-29-57-log
  • innodb_version: 5.7.26-29
  • version_comment: Percona XtraDB集群,发布rel29,修订版03540a3,WSREP版本31.37,wsrep_31.37

显示像‘char%’这样的变量;

代码语言:javascript
复制
character_set_client    utf8
character_set_connection    utf8
character_set_database  latin1
character_set_filesystem    binary
character_set_results   utf8
character_set_server    latin1
character_set_system    utf8
character_sets_dir  /usr/share/mysql/charsets/

有几个来源解释说,company_id索引本身就足以满足这一要求:

我一直无法找到官方文件,确切地说是什么期望。这与id的数据类型有关吗?关于mysql+innodb行为的常识是否不正确?

EN

回答 2

Stack Overflow用户

发布于 2020-08-20 23:29:32

我以前也遇到过这个问题。这是我对它的分析。

  • 它发生在MySQL 5.7和8.0中,但显然不是在旧版本中,也不是在MariaDB中。
  • 我喜欢的“解决方案”是这样修改索引: 索引(Company_id) --删除此索引(company_id,id) --添加以下内容

虽然理论上2列索引与InnoDB的一列索引相同(假设id是PK`‘),但在某些情况下,优化器似乎忽略了这一事实。

此外,当我看到需要时,我喜欢显式地添加PK。这表明模式的未来读者(包括我自己)从附加的PK中获得了一些查询的好处。

我还没有找到“索引合并相交”比等效的复合索引更快的情况。

我不喜欢使用索引“提示”,因为我担心将来数据分布会改变,而我的“提示”会使事情变得更糟。

票数 1
EN

Stack Overflow用户

发布于 2020-08-20 14:00:36

这不管用。

要使keyset分页生效,您需要使用自动增量整数作为主id/key。现在您正在使用VARCHAR和存储UID。

您的查询不会选择"next“UID大于”(... AND id > '525ae038-0cc3-4f9a-85e6-6f36d43fae40' ... )。

当您将主ID更改为number时,这将有效。如果索引仍然存在问题,可以尝试强制mysql使用您的索引:

代码语言:javascript
复制
SELECT * FROM invoice USE INDEX (invoice__company_id_id)
  WHERE company_id = 'someguid' 
    AND id > 12345 
  ORDER BY id
  LIMIT 10
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/57223858

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档