优越的性能、可伸缩性和仪表——Percona MySQL服务器雷竞技下载官网

在MySQL中生成数字序列什么是最简单的方法来生成一个整数序列在MySQL中?换句话说,哪个选择<是>”声明应该我写0,1,2,…N - 1 ?

这是我多年来一直困扰的问题,看来我终于得到了答案(尽管我必须承认我不得不把一些开发工作,并添加一个几百行代码到服务器)。<一个href="//m.doggingzone.com/doc/percona-server/LATEST/release-notes/Percona-Server-8.0.20-11.html">雷竞技下载官网对MySQL 8.0.20-11 Percona服务器包含一个新特性完全致力于解决这个问题。

然而,揭露所有的秘密之前,让我们首先考虑现有的解决方案。所以,我们希望得到以下:

我们选择这样做是什么?

旧的学校方式

让我们先从最简单的解决方案。

联盟的救援

这也许听起来有点原始但最简单的解决方案是结合多个的结果选择声明成一个结果集联盟

尽管这可能适用于较小的数字,这个解决方案不太可扩展。

现有表和一个独特的列

假设我们已经有了一个表,一个独特的列的数据类型。例如:

现在,我们可以将此表与自身的一个副本并选择的数量的记录id在小于或等于副本id在原来的表。

这个解决方案的主要缺点是它的二次复杂性N时,可能会导致显著的资源利用率N是大的。

在选择会话变量增量

前提是我们已经有了一个表t1与前面的示例(尽管这里独特的列约束不是必需的),我们可以加入一个值选择分配一个会话变量初始值。同时,对于每一个现有表的记录,它将增加这个会话变量的值。

这个是不坏:它是可扩展的,线性复杂度N不引入不必要的开销,唯一的缺点是需要有一个现有表。

加入多个视图

我们可以加入多个表(或视图),包含多个记录将记录的总数的结果集。

使用相同的方法,由相交K的实例binary_v我们可以生成的序列2 ^ K值。同样,我们可以创建一个视图为数字和结果10 ^ K值。

虽然这似乎很容易理解,这样一个查询的执行计划绝对是远非完美。

古典风格

存储过程

基本上,在选择之前,我们可以创建一个临时表并填充所需的数字使用预先创建存储过程。

存储过程本身可以定义如下:

这个方法的执行计划几乎是完美的,唯一的缺点是要调用的必要性generate_seq ()使用前的序列。

准备好的语句

让我们试着自动化联盟的解决方案。而不是手动重复联盟条款我们可以动态地生成这个声明。

在哪里generate_seq_stmt ()可以定义如下:

这似乎工作,但是这个解决方案的主要缺点是,它无法直接嵌入到更复杂的查询(除非后者也转化为预备语句)。

顺序存储引擎(MariaDB)

MariaDB另一方面,一个完全不同的方法。而不是扩展SQL语法和发明新结构,<一个href="https://mariadb.com/kb/en/changes-improvements-in-mariadb-100/">版本10.0,他们实现<一个href="https://mariadb.com/kb/en/sequence-storage-engine/">顺序存储引擎时自动创建完全虚拟的,临时表用户需要他们。所有你要做的就是执行以下:

这似乎很明确,然而,保留一个几乎无限数量的表名(seq_ < int1 > _ < int2 >seq_ < int1 > _ < int2 > _ < int3 >)为每个数据库不是很吸引人。例如,你不能做的:

这种方法需要大量的不必要的错误处理和其他分支的服务器代码。他们的文档还提到几个技巧(如ALTER TABLE seq_1_to_100引擎=黑洞)您可以应用为了解决某些问题,但总的来说,他们只是增加更多的复杂性和角落。
就我个人而言,我喜欢语法从< virtual_sequence_generator >选择*,但实施这一构造一个新的存储引擎并不是最好的设计决策。

现代的方式

递归公共表表达式(CTE)

在<一个href="https://dev.mysql.com/doc/relnotes/mysql/8.0/en/news-8-0-1.html">MySQL服务器8.0.1,Oracle引入<一个href="https://dev.mysql.com/doc/refman/8.0/en/with.html">公共表表达式(CTE)非递归和递归的。

尽管这个解决方案可用于一个非常广泛的上界N似乎正是我们所需要的,我怀疑它是可读/容易理解。

从<一个href="https://dev.mysql.com/doc/relnotes/mysql/8.0/en/news-8-0-19.html">8.0.19 MySQL服务器,可以简化这个查询使用限制而不是在哪里

然而,这些解决方案有一个限制。默认情况下,上界N不能很高。

增加<一个href="https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html">cte_max_recursion_depth将这个限制。

值行(…)、行(…)…

如果你是一个幸运的人已经升级到<一个href="https://dev.mysql.com/doc/relnotes/mysql/8.0/en/news-8-0-19.html">MySQL服务器8.0.19,你可以使用一个<一个href="https://dev.mysql.com/doc/refman/8.0/en/values.html">值语句(表值的构造函数,还可以作为一个独立的SQL语句)。

这是一个容易得多联盟的,但仍然缺乏可扩展性。

JSON_TABLE ()

在<一个href="https://dev.mysql.com/doc/relnotes/mysql/8.0/en/news-8-0-4.html">MySQL服务器8.0.4Oracle引入了一个新<一个href="https://dev.mysql.com/doc/refman/8.0/en/json-table-functions.html">JSON_TABLE ()函数,可以从一个JSON文档中提取数据并返回它作为一个关系表的指定列。但是你可能会问这甚至可能是如何生成相关数值序列。让我们考虑下面的例子。

在这里,我们通过一个简单的JSON文档JSON_TABLE ()函数。json文档是一个数组,由一系列对象与预定义的关键“一个”。我们遍历匹配数组的所有元素“[*]美元”JSON路径表达式和提取的值“美元。”键列的类型长整型数字无符号用这个名字价值
虽然在这一点上语法开销是压倒性的,我开始看到隧道尽头的光。

我们可以做的更好,提高我们的第一个JSON_TABLE ()的例子。

在这里,我们有一个空对象数组,使用一个特殊的构造对于ORDINALITY这相当于指定列AUTO_INCREMENT在一个创建表声明。虽然我应该注意到,我们还有一个预定义的空的JSON数组中的对象的数量。<一个href="https://www.imdb.com/title/tt1375666/">这是不够的,我们必须更深。

我们几乎是在那里!

后现代的方式

让我们先总结一下我们设法实现在前面的例子。

  • 清晰的语法构造从JSON_TABLE选择…tt (…)(尽管函数参数仍然是重要的)
  • 我们制作了这个构造生成一个不同的行数取决于的价值@upper_bound变量。
  • 可以使用此构造地方其他派生表声明是被允许的。
  • 不仅这个构造可能依赖于一个会话变量的值,在加入表的情况下,它可能产生不同的从另一个表的行数取决于值的列。

SEQUENCE_TABLE ()

在理想的话,那将是很棒的一个函数,说SEQUENCE_TABLE (),我们的行为是一样的JSON_TABLE (CONCAT(“[{}”,重复(”、{}”@upper_bound - 1),“]”),“[*]美元”列(rowid ORDINALITY)
不幸的是,<一个href="https://dev.mysql.com/doc/relnotes/mysql/8.0/en/news-8-0-19.html">MySQL服务器8.0.19没有这样一个函数。

我必须承认这将是真正可怕的从我这边到结束这篇文章在这一点上,说:“JSON_TABLE()的解决方案是到目前为止最好的我们。这是我们能做的,感谢你的阅读”,所以我不会这样做。
相反,我要宣布<一个href="//m.doggingzone.com/doc/percona-server/LATEST/release-notes/Percona-Server-8.0.20-11.html">雷竞技下载官网Percona服务器8.0.20-11我们实现了一个新的Percona-spec雷竞技下载官网ific特性<一个href="//m.doggingzone.com/doc/percona-server/LATEST/flexibility/sequence_table.html">SEQUENCE_TABLE()的。

长话短说,现在您可以编写以下。

“是的”,你看到它一样简单明了。现在,让我们考虑一个更复杂的例子。
如果我们想从4 - 7生成序列包容吗?

或者,你可以写:

另一个例子,甚至包含数字从0到6:

另外:

另一个例子中,数字从0到3包容在相反的顺序:

另外:

SEQUENCE_TABLE ()也可以用来生成一组随机数:

请注意,使用模式SEQUENCE_TABLE ()不限于数字只。例如,我们可以生成一个预定义的字符串列表(一行转换成一列,如果你愿意)。

或相同的但有重复值:

最后,这个表函数也可以帮助生成伪随机字符串值:

这种构造可以用来填补现有的表:

或者创建一个新的一个预先填写的值:

我确信有很多其他用例(生成斐波纳契数列或打印所有素数在给定的范围内),你肯定能找到你自己的。

结论

在这个博客中,我试图表明,SQL是一个非常强大的语言,让我们做很多的事情。然而,这是非常令人沮丧的,在一些非常简单的情况下,做你想做的事情的唯一方法是使用重型火炮。的例子SEQUENCE_TABLE ()我证明显示,如果添加新功能通过扩展服务器代码是唯一的选择,不要害怕,就可以这样做,尤其是当你知道该怎么做。


解简单的“与Percona服务器启动并运行MySQL”概述了建立一个MySQL®数据库本雷竞技下载官网地使用Percona MySQL服务器。它包括故障转移和基本业务连续性组件。

下载

订阅
通知的
客人

5评论
最古老的
最新的 大多数投票
内联反馈
查看所有评论

就好了如果是sequence_value(结束、开始增量)开始默认为零,增加默认值为1。我假设生成的值是一个for循环,并开始一个序列在一个较高的值(比如我需要10000 - 10010)需要过滤掉很多行where子句。我第一次说这样可以兼容你的当前函数给定一个输入参数。

只是一个想法。

Yura呢Sorokin

贾斯汀,谢谢你的反馈。说实话我们也认为2 -和3-argument版本的这个函数在设计阶段肯定不难实现。一元版本之间的主要问题是在矛盾和二元/三元。作为一名开发人员或DBA和一些编程技巧我希望SEQUENCE_TABLE (N)返回一个从零开始的序列的数字值小于N - 0到N不包容,换句话说在许多编程语言(比如当你指定一个上界发生器)。相比之下,指定SEQUENCE_TABLE (N,米)时,我下意识地希望这个函数返回一个序列从N M包容性。所以,决定实施只有最简单的(1-argument)版本与包容性/ non-inclusive规则避免混淆。
但谁知道呢,总有一个机会,我们将改变这种行为在未来版本的Percona服务器。雷竞技下载官网
顺便说一句,你提到的例子有一个更简单的解决方案,不需要过滤
从SEQUENCE_TABLE选择值+ 10000 tt (11)

R

有几分相似的一个例子。但是惊讶你不提一个简单的:与一列创建一个表。列一个AUTO_INCREMENT列。
完成了。你想下一个序列,并采取添加一行值。

明显的垮台,你有一个表. .但另一方面,它叫显然希望,给你随时访问当前马克斯,很容易让你的下一个序列号。

R

只是增加了我最后的评论. .我想我的用例是不同的。当我使用序列。我想用传统.NEXT_VAL之类的东西,只是得到一个新的独特的号码每一次我想要一个…不只是列出一大串数字。我想这是一个不同的用例,我从来不需要. .也不认为是一个“sequence_number”