获取PostgreSQL中所有序列的最大id

问题描述 投票:0回答:3

我们的数据库有一个监视器来检查 id 是否接近 max-int 或 max-bigint。我们刚刚从 MySQL 迁移过来,我正在努力在 PostgreSQL 上进行类似的检查。我希望有人能帮忙。

这是MySQL中的查询


SELECT table_name, auto_increment FROM information_schema.tables WHERE table_schema = DATABASE();

我正在尝试从 PostgreSQL 获得相同的结果。我们找到了一种方法来做到这一点,通过对数据库的大量调用,单独检查每个表。

我只想对数据库进行 1 次调用。这是我到目前为止所拥有的:

CREATE OR REPLACE FUNCTION getAllSeqId() RETURNS SETOF record AS
$body$
DECLARE
  sequence_name varchar(255);
BEGIN
  FOR sequence_name in SELECT relname FROM pg_class WHERE (relkind = 'S')
  LOOP
      RETURN QUERY EXECUTE 'SELECT last_value FROM ' || sequence_name;
  END LOOP;
  RETURN;
END
$body$
LANGUAGE 'plpgsql';
SELECT last_value from getAllSeqId() as(last_value bigint);

但是,我需要以某种方式将序列名称添加到每个记录中,以便在 [表名称,最后一个值] 或 [序列名称,最后一个值] 的记录中获得输出。

所以我想这样称呼我的函数:

 SELECT sequence_name, last_value from getAllSeqId() as(sequence_name varchar(255), last_value bigint);

我该怎么做?

编辑:在 ruby 中,这将创建我们正在寻找的输出。正如您所看到的,我们执行 1 次调用来获取所有索引,然后对每个索引执行 1 次调用来获取最后一个值。一定有更好的方法。

def perform
  find_auto_inc_tables.each do |auto_inc_table|
    check_limit(auto_inc_table, find_curr_auto_inc_id(auto_inc_table))
  end 
end 

def find_curr_auto_inc_id(table_name)
  ActiveRecord::Base.connection.execute("SELECT last_value FROM #{table_name}").first["last_value"].to_i
end 

def find_auto_inc_tables
  ActiveRecord::Base.connection.execute(
    "SELECT c.relname " +
    "FROM pg_class c " +                                                       
    "WHERE c.relkind = 'S'").map { |i| i["relname"] }
end 
mysql ruby postgresql auto-increment
3个回答
8
投票

你的函数看起来已经很接近了。你想稍微修改一下:

  • 将序列名称包含为文字
  • 返回带有类型列的
    TABLE(...)
    ,而不是
    SET OF RECORD
    ,因为它对调用者来说更容易

这是修订版:

CREATE OR REPLACE FUNCTION getAllSeqId() RETURNS TABLE(seqname text,val bigint) AS
$body$
DECLARE
  sequence_name varchar(255);
BEGIN
  FOR sequence_name in SELECT relname FROM pg_class WHERE (relkind = 'S')
  LOOP
      RETURN QUERY EXECUTE  'SELECT ' || quote_literal(sequence_name) || '::text,last_value FROM ' || quote_ident(sequence_name);
  END LOOP;
  RETURN;
END
$body$
LANGUAGE 'plpgsql';

请注意,

currval()
不是一个选项,因为当未在同一会话中设置序列时它会出错(通过调用
nextval()
,不确定是否还有其他方法)。


0
投票

像这样简单的事情有用吗?

SELECT currval(sequence_name) from information_schema.sequences;

如果你有不是键的序列,我想你可以使用 PG 的序列名称生成模式来尝试限制它。

SELECT currval(sequence_name) from information_schema.sequences
WHERE sequence_name LIKE '%_seq';

如果误报仍然太多,您可以从 information_schema(或我不太了解的 pg_* 模式)中获取表名并优化 LIKE 参数。


0
投票

我偶然发现了这个问题,试图回答我认为OP问的问题:“哪些表有主键翻转的危险?”

此查询检查序列提供的默认值(人们通常配置“id”主键列的方式),并将序列的当前值与主键的容量进行比较,报告前十个以及它们的接近程度:

WITH column_info AS (
  SELECT t.relname AS table_name, c.attname AS column_name, c.atttypid, c.attlen AS length, y.typname AS type
         , pg_get_expr(adbin, adrelid) AS default
         , (regexp_matches(pg_get_expr(adbin, adrelid), 'nextval..(.*).::regclass'))[1] AS sequencename
  FROM pg_class t
  LEFT OUTER JOIN pg_attribute c ON c.attrelid = t.oid
  LEFT OUTER JOIN pg_type y ON y.oid = c.atttypid
  LEFT OUTER JOIN pg_attrdef d ON t.oid = d.adrelid AND d.adnum = c.attnum
  WHERE pg_get_expr(adbin, adrelid) LIKE '%nextval%'
),
max_values(length, max_value) AS (VALUES (4, 2147483647), (8, 9223372036854775807)),
sequence_info AS (
  SELECT table_name, column_name
       , (s.last_value * 100 / m.max_value) percent_of_limit
  FROM column_info ci
  JOIN pg_sequences s ON s.sequencename = ci.sequencename
  JOIN max_values m ON m.length = ci.length
  WHERE s.last_value IS NOT NULL
)
SELECT (table_name || '.' || column_name) AS name,
      percent_of_limit || '%' AS percent
FROM sequence_info
ORDER BY percent_of_limit DESC
LIMIT 10;
© www.soinside.com 2019 - 2024. All rights reserved.