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 主键是否已经处于某种默认顺序 的相关文章

  • MySql 查询在选择中将 NULL 替换为空字符串

    如何用空字符串替换 select 中的 NULL 值 输出 NULL 值看起来不太专业 这是非常不寻常的 根据我的语法 我希望它能够工作 我希望能得到一个解释 为什么没有 select CASE prereq WHEN prereq IS
  • PDO fetch() 失败时会抛出异常吗?

    有没有方法PDO语句 fetch http php net manual en pdostatement fetch php如果 PDO 错误报告系统设置为抛出异常 则在失败时抛出异常 例如 如果我设置 PDO ATTR ERRMODE g
  • SQL Server PIVOT 函数

    我有一个检索所有代理及其模块的查询 结果集将每个模块返回 1 行 SELECT am agentID AS agentid pa agentDisplayName agentdisplayname m ModuleName ModuleNa
  • 将列的值添加到 LIKE 语句中?

    我有 3 个标签表 标签类别和使用过的标签 我想要获取所有标签的列表以及已使用标签的计数 所使用标签的格式是每个具有标签的文档 ID 的逗号分隔值 我一直在尝试类似的方法 但无法将tags tag 字段的值插入到LIKE 语句中 SELEC
  • 选择MySql表数据放入数组中

    我尝试从 mysql 捕获数据并将它们全部放入数组中 认为 users table id name code 1 gorge 2132 2 flix ksd02 3 jasmen skaod2 sql mysql query select
  • 如何检测 Postgres 中持有锁的查询?

    我想不断跟踪 postgres 中的互锁 我碰到锁具监控 https wiki postgresql org wiki Lock Monitoring文章并尝试运行以下查询 SELECT bl pid AS blocked pid a us
  • 从存储过程中的动态 SQL 获取结果

    我正在编写一个存储过程 需要在过程中动态构造 SQL 语句以引用传入的表名称 我需要让这个 SQL 语句返回一个结果 然后我可以在整个过程的其余部分中使用该结果 我尝试过使用临时表和所有内容 但我不断收到一条消息 提示我需要声明变量等 例如
  • php 崩溃后 mysql 表被锁定

    我有一个 MySQL DB 和一个 innoDB 表 我有一个 php 页面 用于连接 锁定表 进行一些更新 然后解锁表 PHP 页面通过 wamp 与 apache 一起提供 php页面将文件上传到数据库 我决定通过上传一个大小大于分配给
  • 物理写入文件已满 - mysql 错误

    我正在使用xampp 每次启动mysql时 我都会在xampp中收到以下错误 Error MySQL shutdown unexpectedly 13 16 14 mysql This may be due to a blocked por
  • SQL 大表中的随机行(使用 where 子句)

    我有一个网站 人们可以在其中对汽车进行投票 向用户展示 4 辆汽车 他 她可以投票选出他们最喜欢的汽车 桌子cars有重要的列 car id int 10 not auto increment so has gaps views int 7
  • 在 MySQL 中将行转置为列

    如何在 MySQL 查询中将行转换为列 您可以将行变成a列与GROUP CONCAT 但您无法以任何自动方式转置整个结果集 您可以编写手动生成每一列的查询 也可以在应用程序中执行此操作 以下是有关编写复杂查询来模拟转置的教程 http ww
  • 更新重复密钥上的复合密钥 [重复]

    这个问题在这里已经有答案了 我需要更新新行 如果两者都满足 date dat and empId who 作为复合键 但如果其中之一或两者不同 则插入 sql INSERT INTO history SET endtimestamp now
  • SQL Server 查询结果集的大小

    SQL Server 中是否有确定结果集中 Mgmt Studio 查询中返回的数据大小 以 MEGS 为单位 您可以打开客户端统计信息 查询菜单 包括客户端统计信息 它给出执行查询时从服务器返回的字节数
  • 如何修复 InterfaceError: 2003: 无法连接到“127.0.0.1:3306:3306”上的 MySQL 服务器(11001 getaddrinfo 失败)

    我的MySQL连接成功但是遇到这个界面错误 import mysql connector db mysql connector connect host 127 0 0 1 3306 user root passwd teja databa
  • PHP/MySQL:如何在网站中创建评论部分[关闭]

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 help reopen questions 我不会问 如何使用 PHP MySQ
  • 我可以在一个查询中更新/选择表吗?

    我需要在查看页面时选择数据并更新 视图 列 有没有一种方法可以在一个查询中执行此操作 或者我是否必须使用不同的查询 如果您不想 不需要使用事务 则可以创建一个存储过程 该过程首先更新视图计数 然后选择值并将其返回给用户
  • 如何使用 PHP 从 MySQL 检索特定值?

    好吧 我已经厌倦了 过去一周我花了大部分空闲时间试图解决这个问题 我知道 SQL 中的查询已更改 但我无法弄清楚 我能找到的所有其他帖子似乎都已经过时了 如果有人能帮助我 我将非常感激 我想做的就是使用手动输入数据库的唯一 密码 来检索行的
  • 如何使用 PHP 获取列中的所有值?

    我一直在到处寻找这个问题 但仍然找不到解决方案 如何从 mySQL 列中获取所有值并将它们存储在数组中 例如 表名称 客户 列名称 ID 名称 行数 5 我想获取此表中所有 5 个名称的数组 我该如何去做呢 我正在使用 PHP 我试图 SE
  • 如何在动态查询中将行值连接到列名

    我正在开发一个允许配置问题和答案的应用程序 目前最多可以有 20 个答案 但也可能更少 我的结构如下 问题 ID FormId QuestionText AnswerField 1 1 Name Answer01 2 1 Address A
  • 哪个是识别关系或非识别关系中的子表?

    在表之间的识别和非识别关系的上下文中 MySQL 文档大量将表称为父表和子表 如何判断哪个表是父表 哪个表是子表 子表 A K A 弱实体 http en wikipedia org wiki Weak entity 是一个表 其主键属性d

随机推荐

  • 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