AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / dba / 问题 / 23879
Accepted
Joe
Joe
Asked: 2012-09-08 01:39:22 +0800 CST2012-09-08 01:39:22 +0800 CST 2012-09-08 01:39:22 +0800 CST

测量 PostgreSQL 表行的大小

  • 772

我有一个 PostgreSQL 表。select *非常慢,但又select id好又快。我认为可能是行的大小非常大并且需要一段时间才能传输,或者可能是其他一些因素。

我需要所有字段(或几乎所有字段),因此仅选择一个子集并不是快速解决方法。选择我想要的字段仍然很慢。

这是我的表架构减去名称:

integer                  | not null default nextval('core_page_id_seq'::regclass)
character varying(255)   | not null
character varying(64)    | not null
text                     | default '{}'::text
character varying(255)   | 
integer                  | not null default 0
text                     | default '{}'::text
text                     | 
timestamp with time zone | 
integer                  | 
timestamp with time zone | 
integer                  | 

文本字段的大小可以是任意大小。但是,在最坏的情况下,不超过几千字节。

问题

  1. 这有什么叫“疯狂低效”的吗?
  2. 有没有办法在 Postgres 命令行中测量页面大小来帮助我调试它?
postgresql disk-space
  • 5 5 个回答
  • 124109 Views

5 个回答

  • Voted
  1. Best Answer
    Erwin Brandstetter
    2012-09-09T08:08:53+08:002012-09-09T08:08:53+08:00

    Q2:way to measure page size

    PostgreSQL 提供了许多数据库对象大小函数。我在这个查询中打包了最有趣的,并在底部添加了一些统计访问函数。(附加模块pgstattuple提供了更多有用的功能。)

    这将表明测量“行大小”的不同方法会导致非常不同的结果。这完全取决于您想要测量的内容。

    此查询需要Postgres 9.3 或更高版本。对于旧版本,请参见下文。

    在子查询中使用VALUES表达式LATERAL,以避免拼写每一行的计算。

    替换public.tbl为可选的模式限定表名,以获得收集的行大小统计信息的紧凑视图。您可以将其包装到 plpgsql 函数中以重复使用,将表名作为参数提交并使用EXECUTE...

    SELECT l.metric, l.nr AS bytes
         , CASE WHEN is_size THEN pg_size_pretty(nr) END AS bytes_pretty
         , CASE WHEN is_size THEN nr / NULLIF(x.ct, 0) END AS bytes_per_row
    FROM  (
       SELECT min(tableoid)        AS tbl      -- = 'public.tbl'::regclass::oid
            , count(*)             AS ct
            , sum(length(t::text)) AS txt_len  -- length in characters
       FROM   public.tbl t                     -- provide table name *once*
       ) x
    CROSS  JOIN LATERAL (
       VALUES
         (true , 'core_relation_size'               , pg_relation_size(tbl))
       , (true , 'visibility_map'                   , pg_relation_size(tbl, 'vm'))
       , (true , 'free_space_map'                   , pg_relation_size(tbl, 'fsm'))
       , (true , 'table_size_incl_toast'            , pg_table_size(tbl))
       , (true , 'indexes_size'                     , pg_indexes_size(tbl))
       , (true , 'total_size_incl_toast_and_indexes', pg_total_relation_size(tbl))
       , (true , 'live_rows_in_text_representation' , txt_len)
       , (false, '------------------------------'   , NULL)
       , (false, 'row_count'                        , ct)
       , (false, 'live_tuples'                      , pg_stat_get_live_tuples(tbl))
       , (false, 'dead_tuples'                      , pg_stat_get_dead_tuples(tbl))
       ) l(is_size, metric, nr);

    结果:

                  公制 | 字节 | 字节漂亮 | bytes_per_row
    ------------------------------------+----------+--- ------------+---------------
     core_relation_size | 44138496 | 42 MB | 91
     可见性地图 | 0 | 0 字节 | 0
     free_space_map | 32768 | 32 KB | 0
     table_size_incl_toast | 44179456 | 42 MB | 91
     索引大小 | 33128448 | 32 MB | 68
     total_size_incl_toast_and_indexes | 77307904 | 74 MB | 159
     live_rows_in_text_representation | 29987360 | 29 MB | 62
     ------------------------------ | | |
     行数 | 483424 | |
     live_tuples | 483424 | |
     死元组 | 第2677章 |

    对于旧版本(Postgres 9.2 或更早版本):

    WITH x AS (
       SELECT count(*)               AS ct
            , sum(length(t::text))   AS txt_len  -- length in characters
            , 'public.tbl'::regclass AS tbl      -- provide table name as string
       FROM   public.tbl t                       -- provide table name as name
       ), y AS (
       SELECT ARRAY [pg_relation_size(tbl)
                   , pg_relation_size(tbl, 'vm')
                   , pg_relation_size(tbl, 'fsm')
                   , pg_table_size(tbl)
                   , pg_indexes_size(tbl)
                   , pg_total_relation_size(tbl)
                   , txt_len
                 ] AS val
            , ARRAY ['core_relation_size'
                   , 'visibility_map'
                   , 'free_space_map'
                   , 'table_size_incl_toast'
                   , 'indexes_size'
                   , 'total_size_incl_toast_and_indexes'
                   , 'live_rows_in_text_representation'
                 ] AS name
       FROM   x
       )
    SELECT unnest(name)                AS metric
         , unnest(val)                 AS bytes
         , pg_size_pretty(unnest(val)) AS bytes_pretty
         , unnest(val) / NULLIF(ct, 0) AS bytes_per_row
    FROM   x, y
    
    UNION ALL SELECT '------------------------------', NULL, NULL, NULL
    UNION ALL SELECT 'row_count', ct, NULL, NULL FROM x
    UNION ALL SELECT 'live_tuples', pg_stat_get_live_tuples(tbl), NULL, NULL FROM x
    UNION ALL SELECT 'dead_tuples', pg_stat_get_dead_tuples(tbl), NULL, NULL FROM x;

    结果相同。

    Q1:anything inefficient?

    您可以优化列顺序以节省每行的一些字节,目前浪费在对齐填充中:

    integer                  | not null default nextval('core_page_id_seq'::regclass)
    integer                  | not null default 0
    character varying(255)   | not null
    character varying(64)    | not null
    text                     | default '{}'::text
    character varying(255)   | 
    text                     | default '{}'::text
    text                     |
    timestamp with time zone |
    timestamp with time zone |
    integer                  |
    integer                  |
    

    这样每行可以节省 8 到 18 个字节。我称之为列俄罗斯方块。看:

    • 为读取性能配置 PostgreSQL
    • 在 PostgreSQL 中计算和节省空间

    还要考虑:

    • 当所有值都是 36 个字符时,使用 char 与 varchar 进行索引查找会明显更快吗
    • 138
  2. Daniel Vérité
    2012-09-08T06:23:02+08:002012-09-08T06:23:02+08:00

    通过查询整行的 TEXT 表示的长度,很容易获得行大小的近似值,包括TOAST的内容:

    SELECT octet_length(t.*::text) FROM tablename AS t WHERE primary_key=:value;
    

    这是执行时将在客户端检索的字节数的近似值:

    SELECT * FROM tablename WHERE primary_key=:value;
    

    ...假设查询的调用者以文本格式请求结果,这是大多数程序所做的(二进制格式是可能的,但在大多数情况下不值得麻烦)。

    可以应用相同的技术来定位N“文本中最大”的行tablename:

    SELECT primary_key, octet_length(t.*::text) FROM tablename AS t
       ORDER BY 2 DESC LIMIT :N;
    
    • 66
  3. Chris Travers
    2012-09-08T04:47:34+08:002012-09-08T04:47:34+08:00

    有几件事可能会发生。一般来说,我怀疑长度是近端问题。我怀疑你有一个与长度相关的问题。

    你说文本字段最多可以达到几k。主存储中的一行不能超过 8k,并且您的较大文本字段可能已被TOASTed或从主存储移出到单独文件中的扩展存储中。这使您的主存储更快(因此 select id 实际上更快,因为要访问的磁盘页面更少)但 select * 变得更慢,因为有更多的随机 I/O。

    如果您的总行大小仍然低于 8k,您可以尝试更改存储设置。但是,我会警告说,在将超大属性插入主存储时可能会发生不好的事情,因此如果您不必这样做,最好不要碰它,如果这样做,请通过检查约束设置适当的限制。所以交通可能不是唯一的事情。它可能正在整理许多需要随机读取的字段。大量随机读取也可能导致缓存未命中,并且所需的大量内存可能需要在磁盘上实现事物和大量宽行,如果存在连接(如果涉及 TOAST,则存在连接)可能需要更昂贵连接模式等

    我要做的第一件事是选择更少的行,看看是否有帮助。如果可行,您也可以尝试向服务器添加更多 RAM,但我会先开始查看由于计划更改和缓存未命中而导致性能开始下降的位置。

    • 16
  4. WhiteFire Sondergaard
    2015-05-01T11:58:19+08:002015-05-01T11:58:19+08:00

    使用上面提到的数据库对象大小函数:

    SELECT primary_key, pg_column_size(tablename.*) FROM tablename;
    

    • 15
  5. FredG
    2020-07-01T06:17:57+08:002020-07-01T06:17:57+08:00

    如果需要当前行大小的平均值,您可以使用 pg_column_size:

    SELECT SUM(pg_column_size(table_name.*))/COUNT(*) FROM tablename;
    

    每列使用它:

    SELECT SUM(pg_column_size(table_name.column_name))/COUNT(*) FROM tablename;
    
    • 6

相关问题

  • 我可以在使用数据库后激活 PITR 吗?

  • 运行时间偏移延迟复制的最佳实践

  • 存储过程可以防止 SQL 注入吗?

  • PostgreSQL 中 UniProt 的生物序列

  • PostgreSQL 9.0 Replication 和 Slony-I 有什么区别?

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    如何查看 Oracle 中的数据库列表?

    • 8 个回答
  • Marko Smith

    mysql innodb_buffer_pool_size 应该有多大?

    • 4 个回答
  • Marko Smith

    列出指定表的所有列

    • 5 个回答
  • Marko Smith

    从 .frm 和 .ibd 文件恢复表?

    • 10 个回答
  • Marko Smith

    如何在不修改我自己的 tnsnames.ora 的情况下使用 sqlplus 连接到位于另一台主机上的 Oracle 数据库

    • 4 个回答
  • Marko Smith

    你如何mysqldump特定的表?

    • 4 个回答
  • Marko Smith

    如何选择每组的第一行?

    • 6 个回答
  • Marko Smith

    使用 psql 列出数据库权限

    • 10 个回答
  • Marko Smith

    如何从 PostgreSQL 中的选择查询中将值插入表中?

    • 4 个回答
  • Marko Smith

    如何使用 psql 列出所有数据库和表?

    • 7 个回答
  • Martin Hope
    Mike Walsh 为什么事务日志不断增长或空间不足? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland 列出指定表的所有列 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney MySQL 能否合理地对数十亿行执行查询? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx 如何监控大型 .sql 文件的导入进度? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison 你如何mysqldump特定的表? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    pedrosanta 使用 psql 列出数据库权限 2011-08-04 11:01:21 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 对 SQL 查询进行计时? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas 如何从 PostgreSQL 中的选择查询中将值插入表中? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 列出所有数据库和表? 2011-02-18 00:45:49 +0800 CST
  • Martin Hope
    bernd_k 什么时候应该使用唯一约束而不是唯一索引? 2011-01-05 02:32:27 +0800 CST

热门标签

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve