PostgreSQL 无间隙序列

2024-04-01

我正在从 MySql 迁移到 Postgres,我注意到当您从 MySql 中删除行时,这些行的唯一 id 在您创建新行时会被重新使用。使用 Postgres,如果您创建行并删除它们,则不会再次使用唯一的 id。

Postgres 中出现这种行为有原因吗?在这种情况下我可以让它表现得更像 MySql 吗?


序列有间隙以允许并发插入。尝试避免间隙或重新使用已删除的 ID 会产生可怕的性能问题。请参阅PostgreSQL 维基常见问题解答 https://wiki.postgresql.org/wiki/FAQ#Why_are_there_gaps_in_the_numbering_of_my_sequence.2FSERIAL_column.3F_Why_aren.27t_my_sequence_numbers_reused_on_transaction_abort.3F.

PostgreSQLSEQUENCEs http://www.postgresql.org/docs/current/static/sql-createsequence.html用于分配ID。这些只会不断增加,并且不受通常的事务回滚规则的约束,以允许多个事务同时获取新的 ID。这意味着如果事务回滚,这些 ID 将被“丢弃”;没有保留“免费”ID 列表,只有当前的 ID 计数器。如果数据库非正常关闭,序列通常也会增加。

合成密钥 (ID) 是无意义的反正。它们的顺序并不重要,它们唯一重要的属性是唯一性。您无法有意义地测量两个 ID 之间的“距离”有多远,也无法有意义地判断一个 ID 是否大于或小于另一个 ID。你所能做的就是说“等于”或“不等于”。其他任何事情都是不安全的。你不应该关心差距。

如果您需要一个重复使用已删除 ID 的无缝序列,您可以拥有一个,只需为此放弃大量性能 - 特别是,您不能在INSERT根本不需要,因为您必须扫描表以查找最低的可用 ID,锁定表以进行写入,这样其他事务就无法声明相同的 ID。尝试搜索“postgresql 无间隙序列”。

最简单的方法是使用计数器表和获取下一个 ID 的函数。这是一个通用版本,它使用计数器表来生成连续的无间隙 ID;但它不会重复使用 ID。

CREATE TABLE thetable_id_counter ( last_id integer not null );
INSERT INTO thetable_id_counter VALUES (0);

CREATE OR REPLACE FUNCTION get_next_id(countertable regclass, countercolumn text) RETURNS integer AS $$
DECLARE
    next_value integer;
BEGIN
    EXECUTE format('UPDATE %s SET %I = %I + 1 RETURNING %I', countertable, countercolumn, countercolumn, countercolumn) INTO next_value;
    RETURN next_value;
END;
$$ LANGUAGE plpgsql;

COMMENT ON get_next_id(countername regclass) IS 'Increment and return value from integer column $2 in table $1';

Usage:

INSERT INTO dummy(id, blah) 
VALUES ( get_next_id('thetable_id_counter','last_id'), 42 );

请注意,当一个打开的事务已获得 ID 时,所有其他尝试调用get_next_id将阻塞,直到第一个事务提交或回滚。对于无间隙 ID,这是不可避免的,并且是设计使然。

如果想在一个表中存储多个不同用途的计数器,只需在上述函数中添加一个参数,在计数器表中添加一列,并添加一个WHERE条款至UPDATE与添加的列的参数相匹配。这样您就可以拥有多个独立锁定的计数器行。做not只需为新计数器添加额外的列即可。

此功能不会重新使用已删除的 ID,它只是避免引入间隙。

要重复使用 ID,我建议...不要重复使用 ID。

如果您确实必须这样做,您可以通过添加ON INSERT OR UPDATE OR DELETE感兴趣的表上的触发器,将已删除的 ID 添加到空闲列表侧表,并在删除它们时将其从空闲列表表中删除INSERT编辑。治疗一个UPDATE as a DELETE随后是一个INSERT。现在修改上面的 ID 生成函数,使其执行SELECT free_id INTO next_value FROM free_ids FOR UPDATE LIMIT 1如果找到的话,DELETE是那行。IF NOT FOUND像平常一样从生成器表中获取一个新的 ID。这是先前函数的未经测试的扩展,以支持重用:

CREATE OR REPLACE FUNCTION get_next_id_reuse(countertable regclass, countercolumn text, freelisttable regclass, freelistcolumn text) RETURNS integer AS $$
DECLARE
    next_value integer;
BEGIN
    EXECUTE format('SELECT %I FROM %s FOR UPDATE LIMIT 1', freelistcolumn, freelisttable) INTO next_value;
    IF next_value IS NOT NULL THEN
        EXECUTE format('DELETE FROM %s WHERE %I = %L', freelisttable, freelistcolumn, next_value);
    ELSE
        EXECUTE format('UPDATE %s SET %I = %I + 1 RETURNING %I', countertable, countercolumn, countercolumn, countercolumn) INTO next_value;
    END IF;
    RETURN next_value;
END;
$$ LANGUAGE plpgsql;
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

PostgreSQL 无间隙序列 的相关文章

  • Rails 3 默认作用域、可覆盖的作用域

    我遇到的情况是现有应用程序的行为正在发生变化 这让我非常头疼 我的应用程序有照片 照片有一个状态 batch queue or complete 应用程序中的所有现有照片都是 完整的 99 的情况下 我只需要显示完整的照片 并且在所有现有代
  • 同一模型之间的两个 has_many 链接

    I have users其中有products通过 habtm 链接 该链接正在运行 我想添加一个链接user模型和product模型 以跟踪creator该产品的 当然 谁并不总是拥有该产品 但是当我写在我的user and produc
  • 如何在 Ruby on Rails 中不使用 eval 将字符串转换为哈希值? [复制]

    这个问题在这里已经有答案了 这里是string需要转换成hash status gt label gt Status collection gt return misc definitions project status 我们不能使用ev
  • Ruby on Rails 中的三重连接

    我对 Ruby on Rails 中的关联有疑问 应用程序中有项目 用户 角色和组 项目属于一个有用户的组 一个用户可以属于多个不同的组 但只能在该组中拥有一个特定的角色 例如 在一个组中 用户是项目所有者 但在另一个组中 他是作家 使用
  • rvm编译安装ruby 2.5.0出错

    我正在尝试使用 rvm 安装 ruby 2 5 0 但出现错误 我在 Ubuntu 18 16 和现在的 Linux Mint Cinnamon 上尝试过 基本上我在运行安装 ruby 的代码之前所做的是 打开 GPG 密钥https rv
  • PSQL [错误] - 值被识别为列

    前几天刚开始学习数据库 我遇到了这个问题 我的值被识别为一列 并且它吐出了一个错误 这是我的News table id bodyText url createdAt updatedAt 这是我在 psql 中运行的命令 INSERT INT
  • Postgres where 子句比较时间戳

    我有一个表 其中列的数据类型timestamp 其中包含一天的多条记录 我想选择与日期对应的所有行 我该怎么做 Assuming you actually mean timestamp because there is no datetim
  • PostgreSQL 如何创建数据库或模式的副本?

    有没有一种简单的方法可以在 PostgreSQL 8 1 中创建数据库或模式的副本 我正在测试一些软件 它对数据库中的特定模式进行大量更新 我想复制它 以便我可以与原始版本进行一些比较 如果它位于同一服务器上 则只需使用带有 TEMPLAT
  • 渲染:带参数的动作

    我有一个有 2 种方法的类 第一个方法由视图使用一些 GET 参数 params page 调用 我想保存这些参数并通过渲染操作将它们发送到我的第二个方法 class exemple def first sql save of params
  • Ruby on Rails - 设计注册链接不起作用 - 未定义方法“user_registration_path”

    这个问题之前已经报告过 但我仍然无法找到解决方案 我已将插件 Devise 安装到我的新 RoR 项目中 当我点击注册链接时 我被重定向到以下路线 http localhost 3000 users registration sign up
  • Rails 4 i18n,如何转换子域用于区域设置的路由

    我正在使用子域来确定 Rails 4 网站中的区域设置 我完全按照我想要的方式使用区域设置切换器 但现在我需要翻译路线 并且我不确定继续的最佳方法 我看过https github com kwi i18n routing https git
  • Mongoid 中的 find_or_create_by 线程安全吗?

    我有一个使用 Mongoid 的 find or create by 方法的网络应用程序 poll Poll find or create by fields 在投入生产之前 我尝试运行故障场景 我发现多个用户可以尝试使用此方法访问此资源
  • 如何从 postgresql 函数或触发器发送一些 http 请求

    我需要通过 http 协议 GET 或 POST 请求 从函数或触发器发送数据 是否可以 您可以尝试用 PL Python 编写触发器并使用 urllib2 进行 POST
  • 当一组工作人员完成时如何执行 Sidekiq 回调

    假设我有一个 Sidekiq 任务将产品处理到我的数据库 每个产品都按商店分组 因此我的代码的一个过于简化的示例将是这样的 stores each do store store products each do product Produc
  • Rails 注释分段错误

    有一些问题围绕着这个问题 但没有什么真正能满足我的需求 After I bundle install下面列出了我的 Gemfile 我运行annotate并出现以下错误 Users nickcoelius rvm gems ruby 1 8
  • 在私有控制器方法中返回redirect_to

    前言 我正在使用设备进行身份验证 我试图阻止未经授权的用户查看 编辑或更新其他用户的信息 我最关心的是用户将 DOM 中的表单修改为另一个用户的 ID 填写表单 然后单击更新 我已经专门阅读过 像下面这样的东西应该有效 但事实并非如此 SO
  • PostgreSQL:比较 json [重复]

    这个问题在这里已经有答案了 众所周知 目前 PostgreSQL 还没有方法来比较两个 json 值 比较就像json json不起作用 但是选角呢json to text before Then select x a y b json t
  • Rails:CSRF 令牌不工作但已设置

    我在 Heroku 上有我的 Rails 3 应用程序 当我发送银行信息时 我得到 WARNING Can t verify CSRF token authenticity但我的 CSRF 令牌已设置 https gist github c
  • postgresql中数组的区别

    我有两个数组 1 2 3 4 7 6 and 2 3 7 在 PostgreSQL 中可能有共同的元素 我想做的是从第一个数组中排除第二个数组中存在的所有元素 到目前为止我已经取得了以下成果 SELECT array SELECT unne
  • Ubuntu 12.04 上的 DeepDive 安装指南

    在拥有以后很多问题 https stackoverflow com questions 22469188 deepdive installation postgresql error安装深潜项目 http deepdive stanford

随机推荐

  • Netbeans 7.4 - 排除 LESS 部分源文件编译为 css

    这主要是一个令人讨厌的问题 在我的 css 目录中造成混乱 我想知道在 Netbeans 7 4 或 8 0 beta 中是否有任何方法可以将 LESS 文件标记为在运行 保存时不进行编译 我有一个library less和vars les
  • 装修调度系统

    我想使用多个处理器并行执行线性运算 将复杂的数学函数拟合到某些数据集 假设我的机器有 8 个核心 我想要容纳 1000 个数据集 我期望的是某个系统将 1000 个数据集作为队列 并将它们发送到 8 个核心进行处理 因此它首先将 1000
  • 根据 Python 中的数组值拆分数组

    我有一个像这样的坐标数组 array 1 6 2 6 3 8 4 10 5 6 5 7 18 6 19 5 17 9 10 5 我想将数组拆分为6 and 7 协调 5 7 18 6 因为有一个间隙X那里的价值 我想得到两个单独的数组 ar
  • 通过intent-Android打开地图显示当前位置的方向

    我的 Android 应用程序中有很多纬度经度 我想知道如何通过意图打开选择器或 Google 地图应用程序 并显示从当前位置到该纬度和经度的方向 就像我有 lat 28 605989 lon 77 372970 并且我当前的位置在某个地方
  • 监控 kubernetes 作业

    我的 Kubernetes 作业需要不同的时间才能完成 4 到 8 分钟之间 有什么方法可以让我知道工作何时完成 而不是在最坏的情况下等待 8 分钟 我有一个执行以下操作的测试用例 1 Submits the kubernetes job
  • Google 云端硬盘 + ACTION_GET_CONTENT

    Google 云端硬盘似乎有一个响应 GET CONTENT 操作的活动 但未导出 我可以在应用程序中使用另一种方法从云端硬盘中提取内容 而无需启动该过程from驾驶 自己编写一个选择器 选择器活动并使用后端 API 列出和打开文件显然是一
  • 函数返回类型不清楚的问题

    我有以下相当简单的 F 函数 let FormatValue formatProvider IFormatProvider valueSuffix value match value gt Convert ToDecimal valueSu
  • 在不同机器上绘制图元文件时缩放比例不同

    我在使用以毫米为测量单位的图元文件的 WinForms 应用程序中获得一致的缩放时遇到问题 我编写了一个小示例应用程序来说明该问题 This is how the application looks on a Windows 7 deskt
  • 函数模板和模板函数有什么区别?

    函数模板和模板函数有什么区别 术语 功能模板 是指一种模板 术语 模板函数 有时用于表示同一事物 有时用于表示从函数模板实例化的函数 最好通过对前者使用 函数模板 和对后者使用 函数模板实例 或 函数模板实例 之类的内容来避免这种歧义 请注
  • 在 UWP (C#) 中尝试运行桌面扩展应用程序时“访问被拒绝”

    我正在尝试运行教程代码FullTrustProcess启动器 https learn microsoft com en us uwp api Windows ApplicationModel FullTrustProcessLauncher
  • R如何计算两行之间的“变化百分比”?

    我喜欢在 Item 时计算 两行之间的变化百分比 行的变化 对于第一行项目 我可以放置一些文本或空白 例如 跳过 或空白都可以 因为没有比较前一行的相同内容 物品 df lt data frame period rep 1 4 2 farm
  • 更改对象列表中的一个元素属性值也会更改所有元素值

    这是我的班级 名为 Objek public class Objek public int id public int tipe public int bentuk public List
  • 托管 WinRT API 是否包含计算 MD5 哈希值的方法? [关闭]

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 help reopen questions 如何在用 C 编写的 Metro S
  • 如何使用 Groovy 从 Oracle 获取游标?

    我正在使用一个Groovy脚本在Mule ESB从中获取输出参数Oracle存储过程 包括游标 并出现异常 最小的例子 import groovy sql Sql import oracle jdbc pool OracleDataSour
  • 如何将 DFM 转换为数据帧但保留文档变量?

    我正在使用 Quanteda 包和有关它的非常好的教程来对纸质文章进行各种操作 我通过在 mainwordsDFM 中选择特定单词并使用textstat frequency mainwordsDFM group Date 然后将结果转换为数
  • 在 Backbone.js 中,为什么静默更改最终会触发更改事件?

    当我经过时 silent true 在 Backbone 模型中设置属性时 为什么不直接抑制change attribute事件 下次更改属性时触发该事件有什么好处 Update Backbone 0 9 10 改变了传递行为 silent
  • 如何在 JavaScript 中四舍五入到最接近的 100

    我想四舍五入到nearest始终为 100 无论该值是 101 还是 199 它都应向上舍入为 200 例如 var number 1233 use something like Math round to round up to alwa
  • 在Excel中检索单元格名称

    有没有办法在另一个单元格中显示特定单元格的单元格名称 我想在相邻单元格中显示单元格名称 以便用户无需单击即可识别单元格名称 此函数将给出单元格所属的 NamedRange 的名称 Public Function CellName oCell
  • IPSec vs OpenSSL vs PGP [关闭]

    Closed 这个问题是无关 help closed questions 目前不接受答案 IPSec 用于 IP 级别 SSL 用于传输级别 PGP 用于应用级别 在一些讲座中不是这样说的 IPSEC 最通用的解决方案 但灵活性最差 SSL
  • PostgreSQL 无间隙序列

    我正在从 MySql 迁移到 Postgres 我注意到当您从 MySql 中删除行时 这些行的唯一 id 在您创建新行时会被重新使用 使用 Postgres 如果您创建行并删除它们 则不会再次使用唯一的 id Postgres 中出现这种