MySQL 主键是否已经处于某种默认顺序

2024-05-02

我刚刚在一个我刚刚开始使用的系统中偶然发现了几行我并不真正理解的代码。该系统有一个大表,可以保存大量具有唯一 ID 的实体,并在不再需要时将其删除,但绝不会重用它们。所以桌子看起来像这样

------------------------
| id |info1|info2|info3|
------------------------
| 1  | foo1| foo2| foo3|
------------------------
| 17 | bar1| bar2| bar3|
------------------------
| 26 | bam1| bam2| bam3|
------------------------
| 328| baz1| baz2| baz3|
------------------------
etc.

在代码库的一个地方有一个 while 循环,其目的是循环遍历数据库中的所有实体并对它们执行操作,现在可以这样解决

int lastId = fetchMaxId()
int id = 0
while (id = fetchNextId()){
  doStuffWith(id)
}

其中 fetchMaxId 是直接的

int fetchMaxId(){
  return sqlQuery("SELECT MAX(id) FROM Table")
}

但 fetchNextId 让我困惑。它的实现为

int fetchNextId(currentId, maxId){
  return sqlQuery("
    SELECT id FROM Table where id > :currentId and id <= :maxId LIMIT 1
  ")
}

这个系统已经投入生产好几年了,所以它显然是有效的,但是当我试图寻找一个解决方案来解释为什么它有效时,我只发现人们说了同样的话,我已经认为我知道了。 MySQL DB 返回结果的顺序不容易确定,也不应该依赖,因此如果您不想要特定的顺序,请使用 ORDER BY 子句。但有时您可以安全地忽略 ORDER BY 吗?该代码已运行 12 年,并在多次数据库更新后继续运行。我们只是幸运还是我在这里错过了什么?在我看到这段代码之前,我会说如果你打电话

fetchNextId(1, 328) 

你最终可能会得到 17 或 26 作为答案。

为什么这样做的一些线索可能是 id 列是相关表的主键,并且它设置为自动增量,但我找不到任何可以解释原因的文档

fetchNextId(1, 328)

当调用上面给出的表片段时,应该总是返回 17。


简短的回答是肯定的,主键有顺序,所有索引都有顺序,主键只是一个唯一索引。

正如您所说,您不应该依赖于按照数据存储的顺序返回数据,优化器可以自由地按照它喜欢的任何顺序返回数据,这将取决于查询计划。不过,我将尝试解释为什么您的查询已经有效了 12 年。

你的聚集索引只是你的表数据,你的聚集键定义了它的存储顺序。数据存储在叶子上,聚集键帮助根(和中间注释)充当指针来快速到达右叶检索数据。非聚集索引是一个非常相似的结构,但最低层仅包含一个指向聚集索引叶上正确位置的指针。

在 MySQL 中,主键和聚集索引是同义词,因此主键是有序的,但它们本质上是两个不同的东西。在其他 DBMS 中,您可以定义主键和聚集索引,当您执行此操作时,您的主键将成为唯一的非聚集索引,并带有返回聚集索引的指针。

用最简单的术语来说,您可以想象一个具有主键 ID 列和另一列 (A) 的表,您的聚集索引的 B 树结构将类似于:

Root Node
                                +---+
                                | 1 |
                                +---+
Intermediate Nodes

                    +---+       +---+       +---+
                    | 1 |       | 4 |       | 7 |
                    +---+       +---+       +---+

Leaf
            +-----------+   +-----------+   +-----------+
    ID ->   | 1 | 2 | 3 |   | 4 | 5 | 6 |   | 7 | 8 | 9 |
    A ->    | A | B | C |   | D | E | F |   | G | H | I |
            +-----------+   +-----------+   +-----------+

实际上,叶子页面会更大,但这只是一个演示。每个页面还有一个指向下一页和上一页的指针,以便于遍历树。因此,当您执行如下查询时:

SELECT ID, A
FROM T
WHERE ID > 5
LIMIT 1;

您正在扫描唯一索引,因此这很可能是顺序扫描。但很可能无法保证。

MySQL将扫描根节点,如果存在潜在的匹配,它将移动到中间节点,如果子句是这样的WHERE ID < 0那么 MySQL 就会知道没有任何结果,而无需超出根节点。

一旦它移动到中间节点,它就可以识别出需要从第二页(4 到 7 之间)开始搜索ID > 5。因此,它将从第二个叶子页开始顺序扫描叶子,已经识别出LIMIT 1一旦找到匹配项(在本例中为 6),它将停止并从叶子返回此数据。在这样一个简单的例子中,这种行为似乎是可靠且合乎逻辑的。我尝试通过选择一个我知道位于叶页末尾的 ID 值来强制异常,以查看叶页是否会以相反的顺序扫描,但到目前为止还无法产生这种行为,但这并不意味着它不会发生,或者 MySQL 的未来版本不会在我测试过的场景中执行此操作。

简而言之,只需添加一个 order by,或使用 MIN(ID) 即可完成。我不会浪费太多时间去深入研究查询优化器的内部工作原理,以了解需要什么样的碎片或数据范围来观察查询计划中聚集索引的不同顺序。

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

MySQL 主键是否已经处于某种默认顺序 的相关文章

  • 在 SQL Server 中通过标准差消除异常值

    我试图通过标准差消除 SQL Server 2008 中的异常值 我只想要特定列中包含该列平均值的 1 标准差范围内的值的记录 我怎样才能做到这一点 如果您假设事件呈钟形曲线分布 则只有 68 的值与平均值相差 1 个标准差以内 95 的值
  • 通过Java从MySQL中获取大量记录

    有一个 MySQL 表 服务器上的用户 它有 28 行和 100 万条记录 也可能会增加 我想从这个表中获取所有行 对它们进行一些操作 然后将它们添加到 MongoDB 中 我知道通过简单的 从用户中选择 操作来检索这些记录将花费大量时间
  • MySQL 复制是双向的

    我们已经成功设置了 MySQL 文献中描述的主从复制 不过 我很好奇是否有人设置了双向复制 例如 如果安装了 Drupal 或 Wordpress 第一个 主 数据库服务器出现故障 第二个 从属 数据库服务器恢复正常 与此同时 用户不断进行
  • 验证 sql/oracle 中的电子邮件/邮政编码字段

    对于以下方面的一些建议将不胜感激 是否可以通过 oracle 中的 sql 中的某种检查约束来验证电子邮件和邮政编码字段 或者我怀疑 pl sql 带有正则表达式的这种事情 Thanks 这是电子邮件地址的正则表达式语法 包括引号 a zA
  • 如何根据同一个表中的先前数据更新 SQL 表

    我有一张衡量学生表现的表格student在我的数据库中如下 ID TestDate PerformanceStatus PS 1 15 03 2016 0 1 01 04 2016 2 1 05 05 2016 1 1 07 06 2016
  • SQL 按计数排序

    如果我有一个表和这样的数据 ID Name Group 1 Apple A 2 Boy A 3 Cat B 4 Dog C 5 Elep C 6 Fish C 我希望根据 Group 的总和从小到大进行排序 例如 A 2条记录 B 1条记录
  • 我应该如何审核 MySQL 表中的更改(使用 MySQL 4)?

    我被要求审核 MySQL 表中的任何 所有更改 有谁知道有什么工具可以帮助我做到这一点 还是我需要编写自己的解决方案 如果我编写自己的审计 我最初的想法是制作一个单独的表并在 PHP 代码中构建一系列更改 类似 fieldname1 gt
  • R:ifelse 中的字符串列表

    我正在寻找与 MySQL 中的 where var in 语句类似的东西 我的代码如下 data lt data frame id 10001 10030 cc1 rep c a b c 10 attach data data new lt
  • Oracle如何将UTC时间转换为本地时间(缺少偏移信息)

    我有一个包含日期列的表 我认为该列中的日期是以 UTC 格式保存的 我希望检索日期时以当地时间打印 这意味着当我从德国调用日期时 结果应该是这样的 2015 04 29 11 24 06 0200UTC EUROPE BERLIN 我尝试了
  • sql join 告诉我 ID 是否存在于其他表中

    我有 2 张桌子 A B ID FKID 1 3 2 3 3 4 4 4 我需要一个 select 语句 它显示 A 的所有内容 其中一个字段告诉我表 B 是否有任何与该 ID 匹配的 id Desired Result ID hasB 1
  • PHP,文本从数据库中回显,没有换行,全部一体

    我的数据库中有一个长文本 从 php mayadmin 来看它看起来很好 但是当我将它回显到页面时 它会丢失所有格式 即没有新行 全部都在一个块中 有任何想法吗 Thanks 可能是因为换行符是 n 并且 html 想要 br 所以使用nl
  • 优化 LATERAL join 中的慢速聚合

    在我的 PostgreSQL 9 6 2 数据库中 我有一个查询 该查询根据一些股票数据构建计算字段表 它为表中的每一行计算 1 到 10 年的移动平均窗口 并将其用于周期性调整 具体来说 CAPE CAPB CAPC CAPS 和 CAP
  • 使用 Flot、html、PHP 和 MySql 查询绘制多个图表

    我正在尝试使用 Flot html PHP 和 MySql 查询绘制多个图表 但我陷入了困境 因为我找不到在同一个 html 页面中绘制多个 flot 的方法 为简单起见 在数据库 test db3 映像中包含以下字段 表1 用户名 发送邮
  • MySQL:所有表都正常,但仍然错误 1577(发现事件调度程序使用的系统表已损坏)

    从我的系统日志 mysql 1663 ERROR 1577 HY000 at line 1 Cannot proceed because system tables used by Event Scheduler were found da
  • 打印表数据mysql php

    我在尝试打印表格的一些数据时遇到问题 我是 php mysql 的新手 但我认为我的代码是正确的 这里是 h1 Lista de usu rios h1
  • 如何将 sql 数据输出到 QCalendarWidget

    我希望能够在日历小部件上突出显示 SQL 数据库中的一天 就像启动程序时突出显示当前日期一样 在我的示例中 它是红色突出显示 我想要发生的是 当用户按下突出显示的日期时 数据库中日期旁边的文本将显示在日历下方的标签上 这是我使用 QT De
  • Oracle 按月滚动或运行总计

    目标 每个月末所有报表的滚动 运行总计 Code select TRUNC ACTHX STMT HX STMT DATE MM AS MNTH COUNT ACTHX INVOICE as STMTS from ACTHX group b
  • RANK() OVER PARTITION 并重置 RANK

    如何获得在分区更改时重新启动的 RANK 我有这张表 ID Date Value 1 2015 01 01 1 2 2015 01 02 1
  • 如何将事物的组合映射到关系数据库?

    我有一个表 其记录代表某些对象 为了简单起见 我假设该表只有一列 这是唯一的ObjectId 现在我需要一种方法来存储该表中的对象组合 组合必须是唯一的 但可以是任意长度 例如 如果我有ObjectIds 1 2 3 4 我想存储以下组合
  • 使用 md5 加密的 PHP 和 Mysql 查询出现问题

    我使用普通的 php mysql 插入查询并使用 md5 加密密码 这是插入查询 sql mysql query INSERT INTO user username password role approved values usernam

随机推荐

  • IntelliJ Idea 15 显示依赖包和项目包

    IntelliJ Idea 15 CE 在项目的包视图中显示来自库 依赖项的包 仅当项目的根包与某些依赖项的根包相同时才会发生这种情况 对于前 我的项目的根包是org 所以所有的依赖关系也有org包状org apache logging也被
  • 如何在 React 中使用原生 Node.js 插件

    我有一个反应项目 我想在其中使用this https github com svenpaulsen node ts3sdk client原生 Node js 插件 它是 C SDK 的包装器 我过去曾在 Electron 项目中成功使用过此
  • Jenkins 的 Gerrit 触发器找不到任何要构建的修订

    我在使用 Jenkins Gerrit 时遇到问题 这是我到目前为止得到的 Jenkins 中的 Gerrit 触发器配置似乎没问题 当我推送新的变更集时 Jenkins 构建就会启动 我用过这个 Jenkins Gerrit 触发器问题的
  • 旋转时键盘隐藏

    我正在开发 iPad 应用程序 在其中一个视图中 我有一个子视图 它在按钮点击事件时出现和消失 子视图包含一个UITextView 默认情况下 我将其设置为第一响应者 以便在视图出现时键盘立即出现 子视图也会消失UIKeyboardWill
  • 尝试添加到链接列表时,Valgrind 无限循环“信号 11 被丢弃”

    我正在尝试用 C 创建一个简单的单链表 并且在 Valgrind 中运行程序时遇到无限的 Singal 11 被删除 循环 我的 h 文件 ifndef TEST H define TEST H struct fruit char name
  • 使用 Qt 进行拖放:悬停时了解目标应用程序 - 这可能吗?

    我目前正在探索从 Qt 应用程序拖放到未知目标应用程序的可能性 问题是 Qt 应用程序是否可以接收有关即将接收 drop 的应用程序的信息 例如进程名称或标题 一个 虚构的 示例可以是将绘图从 Qt 窗口拖动到文本编辑器或电子表格编辑器 在
  • 通用存储库是否需要一个基实体类才能在任何地方应用?

    我正在使用 ASP NET MVC 创建一个 Intranet 网站洋葱架构 我一直在实现存储库模式 但遇到了困难 假设我有一个包含 IDDocument 的文档表 那么这是我的存储库 只有一种方法 class Repository
  • 如何使用react-router通过路由将props传递给react组件?

    我想将一些道具传递给 IndexRoute 上的组件 下面是我的代码片段 render root Element const store params this as any ReactDOM render
  • 键盘友好的 CSS 菜单

    我的问题是这个问题的续集 键盘可访问的网络下拉菜单 https stackoverflow com questions 3945490 keyboard accessible web dropdown menus 虽然上述问题表明 我们想出
  • Erlang 更好地支持哪种数据库(SQL)?

    你建议我在 Erlang 中使用什么 MySQL 还是 Postgres 哪个数据库有更好 更成熟 更稳定 更快 的 Erlang 驱动程序 The Erlang ODBC 接口 http erlang org doc apps odbc
  • 获取键列表的值列表

    是否有一种内置 快速的方法来使用字典的键列表来获取相应项目的列表 例如我有 gt gt gt mydict one 1 two 2 three 3 gt gt gt mykeys three one 我该如何使用mykeys以列表形式获取字
  • 使用 MapKit ios 绘制渐变折线

    我正在尝试使用叠加层 MKOverlay 跟踪 MKMapView 上的路线 但是 根据当前的速度 如果颜色发生变化 例如 如果用户从 65 英里每小时行驶到 30 英里每小时 则从绿色变为橙色 我希望在跟踪路线时执行类似 Nike 应用程
  • 使用 DrawImage 方法黑屏

    我必须使用绘制位图图像绘图上下文 DrawImage http msdn microsoft com en us library ms606804 28v vs 90 29 aspx method 使用下面的代码一切正常 BitmapIma
  • dplyr 中的 if_all 和 if_any 函数未运行

    我正在尝试使用以下方法复制这些示例if all and if any功能但不工作 Erro Problem with filter input 1 x n o foi poss vel encontrar a fun o if all i
  • 如何在收到一定数量的数据后调用 Web 服务并将其加载到表视图中

    我正在开发一个项目 在该项目中 首先调用 Web 服务 我们会获取大约 20 个数据 我们将这些数据加载到表视图中 一旦我们开始向上滚动查看视图 当它达到 20 个数时 我们需要为接下来的 20 个数调用服务 就像 Facebook 所做的
  • grails 中的 log4j:在附加程序配置中使用变量时打印错误

    我在 grails 2 3 4 中使用 slf4j DailyRollingFileAppender 当我尝试使用变量作为 文件 参数的一部分时 grails 总是在应用程序启动时打印一些错误日志 但是我的应用程序的日志消息可以按预期打印到
  • java.lang.ClassCastException:android.os.Parcelable[] 无法转换为 Photo[]

    It s happening for 0 08 of our users One of the crashes happening on Samsung Galaxy S10 running Android 11 不过 在运行 Androi
  • 使用带有 Razor Pages 的复选框列表作为数据库的输入

    我希望表单中的输入之一来自用户选择的复选框列表 我已经研究了几个小时了 但我仍然不明白我需要为此做什么 为什么 MVC 在这个主题上有如此多的帮助 而 Razor 却几乎没有 cshtml
  • Gson:解析通用集合

    是否可以创建一个从 jsson 解析通用集合的方法 我上面的方法不起作用 因为在运行时 gson 在此处返回 LinkedHasmaps 的 ArrayList 但是在编译时没有错误 private
  • MySQL 主键是否已经处于某种默认顺序

    我刚刚在一个我刚刚开始使用的系统中偶然发现了几行我并不真正理解的代码 该系统有一个大表 可以保存大量具有唯一 ID 的实体 并在不再需要时将其删除 但绝不会重用它们 所以桌子看起来像这样 id info1 info2 info3 1 foo