mysql 中键集分页的索引

2024-03-02

我正在尝试在 mysql 中构建索引以支持键集分页查询。我的查询如下所示:

SELECT * FROM invoice 
  WHERE company_id = 'someguid' 
    AND id > 'lastguidfromlastpage' 
  ORDER BY id
  LIMIT 10

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

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 添加到索引中,那么我会得到我期望的解释计划:

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)

显示创建表:

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;

use_index_extensions=on

MySQL版本:

  • 版本:5.7.26-29-57-log
  • innodb_版本:5.7.26-29
  • version_comment:Percona XtraDB Cluster (GPL),版本 rel29,修订版 03540a3,WSREP 版本 31.37,wsrep_31.37

显示类似“char%”的变量;

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 索引本身就足够了:

  • https://stackoverflow.com/a/30152513/64023 https://stackoverflow.com/a/30152513/64023
  • https://dba.stackexchange.com/a/136029/166838 https://dba.stackexchange.com/a/136029/166838

我一直无法找到有关具体预期内容的官方文档。这与 id 的数据类型有关吗?关于mysql+innodb行为的常识不正确吗?


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

  • 它出现在 MySQL 5.7 和 8.0 中,但显然不会出现在旧版本中,也不会出现在 MariaDB 中。

  • 我更喜欢的“解决方案”是更改索引:

       INDEX(company_id)      -- DROP this
       INDEX(company_id, id)  -- ADD this
    

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

另外,我喜欢明确添加 PK当我看到需要时。这向该架构的未来读者(包括我自己)发出信号,表明某些查询受益于附加的 PK。

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

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

mysql 中键集分页的索引 的相关文章

随机推荐

  • Ruby Savon Gem 更改日志记录配置

    我尝试在针对 WSDL 运行 Savon 时更改其日志记录 但更改日志记录级别未成功 我阅读了文档 http rubiii github com savon global configuration http rubiii github c
  • 如果使用相同的数组作为两个参数,strcat() 会崩溃

    char r 40 strcpy r abcdef strcat r r 我的程序在第三行崩溃了 替换 strcat r r 通过 strcat r abcdef 不过工作正常 这是为什么 根据strcat 3 http linux die
  • Django 管理模板覆盖不起作用

    姜戈 1 6 11 应用程序结构如下所示 my project new app templates 在我的配置中 TEMPLATE ROOT os path join BASE ROOT templates TEMPLATE DIRS TE
  • 匹配枚举引用的语法是什么?

    似乎 Rust 的每一份介绍性文档枚举类型 https doc rust lang org book first edition enums html解释如何match https doc rust lang org book first
  • 如何将S3中的10,000个文件公开

    我的存储桶中有一个文件夹 其中包含 10 000 个文件 似乎没有办法立即上传并公开它们 所以我把它们全部上传了 它们是私人的 我需要将它们全部公开 我尝试过 aws 控制台 它只是给出一个错误 对于文件较少的文件夹工作正常 我尝试过在 F
  • 如何从您的脚本执行另一个 python 脚本并能够进行调试?

    您有包装器 python 脚本正在调用另一个 python 脚本 当前正在使用os system python another py some params 您希望能够调试这两个脚本 并且如果您使用os system 您将丢失调试器 因此使
  • C 扩展中 IO 有界线程的 GIL (HDF5)

    我有一个采样应用程序 它获取250 000每秒采样 将它们缓冲在内存中并最终附加到HDFStore由 提供pandas 总的来说 这很棒 但是 我有一个线程运行并不断清空数据采集设备 DAQ 并且它需要定期运行 大约一秒的偏差往往会破坏东西
  • React Native嵌套ListView在加载时多次触发onEndReached

    这是代码
  • Windows 文件关联是否正确完成?

    我想将我的应用程序设置为在 Windows 中具有文件关联 额外的复杂性 文件扩展名可能与其他一些不相关的应用程序冲突 处理这种情况的最佳方法是什么 用户很可能不会同时拥有这两者 但如果两者兼得 最好的处理方式是什么 我一直在网上搜索 st
  • 舍入 ** 0.5 和 math.sqrt

    在 Python 中 是 n 0 5 or math sqrt n 当一个数是完全平方数时被识别 具体来说 我应该担心当我使用 int n 0 5 instead of int n 0 5 0 000000001 由于精度误差 我可能会意外
  • gcc 在 Cygwin 上安装 Python MySQL 库失败

    我想安装oursql or MySQLdb在 Cygwin 盒子上 皮维基机器人 https www mediawiki org wiki Manual Pywikibot可以与任何一个一起工作 不幸的是两者easy install也pip
  • 如何在 Formik Validations Reactjs 中添加单选按钮?

    我正在使用 Formik 验证我的注册表单 我想通过单选按钮添加验证性别 我该怎么做 我无法添加单选按钮 这就是我所做的 const SignupSchema Yup object shape email Yup string email
  • 类库中的可移植 XAML 样式

    所以我有一个应用程序 其样式直接放入 App xaml 文件中 如下所示
  • 如何在Web API中获取POST数据?

    我以以下形式向服务器发送请求 http localhost 12345 api controller par1 par2 该请求被正确解析为如下方法 HttpPost public void object Post string par1
  • 为什么“git bisect”分支不知道?

    我正在尝试找到自过去一天在一个长期存在的分支 将在很久以后发布 上提交以来出现的错误的来源 该分支称为特征 x 但有一个错误 我发现我的脚本中没有预期的行为 到目前为止 这些行为可能已在任何提交中引入 特别是因为 master 的功能在 f
  • 让 Hyper-V 和 Intel HAXM 共存

    Windows Phone 模拟器需要 Hyper V 才能运行 但 Android 模拟器又需要 Intel 硬件加速管理器 HAXM 而后者无法兼容 Hyper V 有没有办法保持 Hyper V 并暂时禁用它以使 Intel HAXM
  • 如何使用 Jenkins http-request 插件和 Pipeline 在正文中 POST JSON 数据?

    使用 Jenkins 的 http request 插件 v1 8 10 我运行的是 1 643 现在支持在请求中 POSTing 正文 所以这thread https stackoverflow com questions 3608242
  • Python 中 += 是什么意思?

    我在 Python 中看到这样的代码 if cnt gt 0 and len aStr gt 1 while cnt gt 0 aStr aStr 1 aStr 0 cnt 1 什么是 mean a b本质上是一样的a a b 除了那个 总
  • 获取连接到Web服务器的客户端的用户名

    这是场景 我的代码在 AD 域中的 Web 服务器上运行 一些客户已连接到我 如何获取该客户的用户名 而不让客户在浏览器中填写表格 Web服务器端必须使用Java技术 edit 我最终使用了 Spring Security Negotiat
  • mysql 中键集分页的索引

    我正在尝试在 mysql 中构建索引以支持键集分页查询 我的查询如下所示 SELECT FROM invoice WHERE company id someguid AND id gt lastguidfromlastpage ORDER