小编tom*_*mka的帖子

在大型 PostgresSQL 表中提高 COUNT/GROUP-BY 的性能?

我正在运行 PostgresSQL 9.2 并且有一个 12 列的关系,大约有 6,700,000 行。它包含 3D 空间中的节点,每个节点都引用一个用户(创建它的人)。要查询哪个用户创建了多少个节点,我执行以下操作(添加explain analyze以获取更多信息):

EXPLAIN ANALYZE SELECT user_id, count(user_id) FROM treenode WHERE project_id=1 GROUP BY user_id;
                                                    QUERY PLAN                                                         
---------------------------------------------------------------------------------------------------------------------------
 HashAggregate  (cost=253668.70..253669.07 rows=37 width=8) (actual time=1747.620..1747.623 rows=38 loops=1)
   ->  Seq Scan on treenode  (cost=0.00..220278.79 rows=6677983 width=8) (actual time=0.019..886.803 rows=6677983 loops=1)
         Filter: (project_id = 1)
 Total runtime: 1747.653 ms
Run Code Online (Sandbox Code Playgroud)

如您所见,这大约需要 1.7 秒。考虑到数据量,这还算不错,但我想知道这是否可以改进。我尝试在用户列上添加 BTree 索引,但这没有任何帮助。

您有其他建议吗?


为了完整起见,这是完整的表定义及其所有索引(没有外键约束、引用和触发器):

    Column     |           Type           |                      Modifiers                    
---------------+--------------------------+------------------------------------------------------
 id            | bigint                   | not null default nextval('concept_id_seq'::regclass)
 user_id       | bigint …
Run Code Online (Sandbox Code Playgroud)

postgresql performance index count group-by

28
推荐指数
2
解决办法
6万
查看次数

如何在交易 ID 环绕后比较 xmin 和 txid_current()?

除了常规列之外,Postgres 表还有各种可用的系统列。其中之一,xmin,存储用于创建行的事务 ID。它的数据类型是xid,一个四字节整数,在某个点环绕(即不一定是唯一的)。该函数txid_current()反过来返回当前事务 ID,但作为bigint,因为它“使用“纪元”计数器进行了扩展,因此它不会在安装的生命周期内回绕”(引用手册)。

如果尚未发生交易回绕,则两个值似乎都匹配:

# CREATE TABLE test (label text);
CREATE TABLE
# INSERT INTO test VALUES ('test') RETURNING txid_current();
 txid_current 
--------------
   674500
(1 row)
INSERT 0 1
# SELECT xmin FROM test;
  xmin  
--------
 674500
(1 row)
Run Code Online (Sandbox Code Playgroud)

但我想知道:这两个值总是具有可比性吗?据我了解,txid_current()将在交易 ID 环绕(最多 2^32 个交易)后继续提供唯一值,xmin并将从零开始。这意味着两者都在那时开始返回不同的值?

如果这是真的,有没有办法来提取规则xid一的txid_current()结果,以便它匹配xmin的表(例如铸造项目txid_current(),以整数)?

编辑:更清楚地说明我关心事务 ID 环绕之后会发生什么,这很可能发生在 2^32 事务之前很久。感谢 Daniel Vérité 在评论中指出这一点。

postgresql transaction postgresql-9.5

13
推荐指数
1
解决办法
6120
查看次数

将 INCLUDE 项添加到 Postgres 11 中的主键索引

我使用 Postgres 11 并想更改支持大表(约 7.5 亿行)主键的索引。主键是bigintid,我想使用该INCLUDE术语包含一个额外的列。这需要在没有表重写的情况下发生(即没有新的/更改的列)。

删除当前PRIMARY KEY约束并不方便,因为很多其他表都引用了目标表。我想可以删除FOREIGN KEY所有这些表的PRIMARY KEY约束,然后删除约束,使用新索引重新创建,然后重新创建FOREIGN KEY约束。有没有更好的方法来做到这一点?

postgresql index constraint index-tuning

6
推荐指数
1
解决办法
709
查看次数

Postgres 中空间查询的 3d 点数据的良好布局?

就像另一个问题所示,我在 3D 空间中处理了很多(> 10,000,000)个点条目。这些点定义如下:

CREATE TYPE float3d AS (
  x real,
  y real,
  z real);
Run Code Online (Sandbox Code Playgroud)

如果我没记错的话,需要 3*8 字节 + 8 字节填充(MAXALIGN是 8)来存储这些点之一。有没有更好的方法来存储这种数据?在前面提到的问题中,有人指出复合类型涉及相当多的开销。

我经常做这样的空间查询:

  SELECT t1.id, t1.parent_id, (t1.location).x, (t1.location).y, (t1.location).z,
         t1.confidence, t1.radius, t1.skeleton_id, t1.user_id,
         t2.id, t2.parent_id, (t2.location).x, (t2.location).y, (t2.location).z,
         t2.confidence, t2.radius, t2.skeleton_id, t2.user_id
  FROM treenode t1
       INNER JOIN treenode t2 ON
         (   (t1.id = t2.parent_id OR t1.parent_id = t2.id)
          OR (t1.parent_id IS NULL AND t1.id = t2.id))
        WHERE (t1.LOCATION).z = 41000.0
          AND (t1.LOCATION).x > 2822.6
          AND (t1.LOCATION).x …
Run Code Online (Sandbox Code Playgroud)

postgresql datatypes spatial composite-types

5
推荐指数
1
解决办法
2284
查看次数

对齐优化表比原始表大 - 为什么?

另一个问题中,我了解到我应该从我的一个表中优化布局以节省空间并获得更好的性能。我这样做了,但最终得到了比以前更大的表,并且性能没有改变。当然我做了一个VACUUM ANALYZE. 怎么会?

(我看到如果我只索引单列,索引大小不会改变。)

这是我来自的表(我添加了尺寸 + 填充):

                               Table "public.treenode"
    Column     |           Type           | Size |          Modifiers
---------------+--------------------------+------+-------------------------------
 id            | bigint                   | 8    | not null default nextval( ...
 user_id       | integer                  | 4+4  | not null
 creation_time | timestamp with time zone | 8    | not null default now()
 edition_time  | timestamp with time zone | 8    | not null default now()
 project_id    | integer                  | 4    | not null
 location      | real3d                   | 36   | …
Run Code Online (Sandbox Code Playgroud)

postgresql database-design datatypes disk-space vacuum

5
推荐指数
1
解决办法
1019
查看次数

PL/pgSQL regclass 引用名为 like 关键字的表

我想通过在现有表名的基础上附加后缀来创建一个新表名。Postgres 9.5 PL/pgSQL 函数获取作为regclass类型传入的现有表名,并以字符串形式返回新名称。我format()用来构造新名称,通常会使用%I占位符。只要传入的表名不匹配任何 PL/pgSQL 关键字,这就会起作用。在这种情况下,无论我选择(%I%s)什么类型的组件,引用都是错误的。

考虑以下函数:

CREATE OR REPLACE FUNCTION make_name(old_name regclass)
RETURNS text                                           
LANGUAGE plpgsql AS                                    
$$                                                     
BEGIN                                                  
    RETURN format('%I_new', old_name);                 
END;                                                   
$$;                                                    
Run Code Online (Sandbox Code Playgroud)

进一步假设有两个表:treenodeoverlay。为这两个函数调用此函数会产生以下新名称:

SELECT make_name('overlay'::regclass);
     make_name     
-------------------
 """overlay"""_new
(1 row)

SELECT make_name('treenode'::regclass);
  make_name   
--------------
 treenode_new
(1 row)
Run Code Online (Sandbox Code Playgroud)

事实证明overlay它也是一个 PL/pgSQL 函数(就像format,但treenode不是),它似乎改变了引用行为。如果%s与 一起使用format(),结果将是"overlay"_new。当我使用||运算符时也会发生同样的情况。如果我使用text作为输入参数类型,一切都按预期工作,但我更喜欢使用regclass.

有没有办法用不带引号的关键字匹配regclass表名(例如overlay …

postgresql syntax datatypes plpgsql regclass

5
推荐指数
1
解决办法
2087
查看次数