【问题标题】:Postgresql View - Performance with fewer columnsPostgresql 视图 - 列更少的性能
【发布时间】:2020-04-24 13:31:00
【问题描述】:

列数越少的视图越快,性能越好吗?

在此示例 CREATE VIEW 中,SELECT 仅包含项目迫切需要的列(表“d”中六列中的两列)。

CREATE VIEW data_with_form_id AS (
SELECT
  e.form_id, d.fld, d.val

我不想短视;我可以轻松添加元列:

CREATE VIEW data_with_form_id AS (
SELECT
  e.form_id, d.*

但这对视图的性能有什么影响?

我搜索了“postgresql 视图性能”,其中包含一些用于选择和列的术语,但仅搜索“postgresql”和“性能”会导致很多结果,以至于在@987654325 中找到有关列数的视图性能的任何信息@ 是针在(许多领域)的干草堆比例。

【问题讨论】:

    标签: postgresql view database-performance


    【解决方案1】:

    获取不需要的列肯定会额外花费,尽管该成本通常可以忽略不计。但获取的列取决于使用视图的查询,而不是视图定义。

    不过,向视图中添加新列并不难。

    为了扩展获取列的成本,获取第 40 列比获取第二列更昂贵。获取在 TOAST 表中存储的超大列特别昂贵。

    【讨论】:

      【解决方案2】:

      表定义+样本数据:

      \i tmp.sql
      
      CREATE table eee
              ( form_id SERIAL NOT NULL PRIMARY KEY
              , payload char (500)
              );
      
      INSERT INTO eee(payload)
      SELECT 'payload_'|| gs::text
      FROM generate_series(1,100) gs;
      
      CREATE table ddd
              ( id SERIAL NOT NULL PRIMARY KEY
              , form_id SERIAL NOT NULL REFERENCES eee(form_id)
              , fld char (100)
              , val char (200)
              , trash char (400)
              , filth char (800)
              );
      CREATE INDEX ON ddd(form_id);
      
      
      INSERT INTO ddd(form_id, fld,val,trash,filth)
      SELECT eee.form_id
              , 'fld_'|| gs::text
              , 'val_'|| gs::text
              , 'trash_'|| gs::text
              , 'filth_'|| gs::text
      FROM eee
      JOIN generate_series(1,10) gs ON random() < 0.3
              ;
      
      VACUUM ANALYZE eee;
      VACUUM ANALYZE ddd;
      

      两个视图:

      CREATE VIEW v1 AS
      SELECT e.form_id
              , d.fld, d.val
      FROM eee e
      JOIN ddd d ON d.form_id = e.form_id
              ;
      
      CREATE VIEW v0 AS
      SELECT e.payload
              , d.*
      FROM eee e
      JOIN ddd d ON d.form_id = e.form_id
              ;
      

      让我们试试吧:

      \echo v1 complete
      EXPLAIN SELECT * FROM v1 ;
      \echo v1 three fields
      EXPLAIN SELECT form_id,fld, val FROM v1 ;
      
      \echo v0 complete
      EXPLAIN SELECT * FROM v0 ;
      \echo v0 three fields
      EXPLAIN SELECT form_id,fld, val FROM v0 ;
      \echo v0 four fields
      EXPLAIN SELECT form_id,fld, val,trash FROM v0 ;
      

      输出:

      DROP SCHEMA
      CREATE SCHEMA
      SET
      CREATE TABLE
      INSERT 0 100
      CREATE TABLE
      CREATE INDEX
      INSERT 0 309
      VACUUM
      VACUUM
      CREATE VIEW
      CREATE VIEW
      v1 complete
                                             QUERY PLAN                                        
      -----------------------------------------------------------------------------------------
       Hash Join  (cost=5.09..71.03 rows=309 width=309)
         Hash Cond: (d.form_id = e.form_id)
         ->  Seq Scan on ddd d  (cost=0.00..65.09 rows=309 width=309)
         ->  Hash  (cost=3.84..3.84 rows=100 width=4)
               ->  Index Only Scan using eee_pkey on eee e  (cost=0.14..3.84 rows=100 width=4)
      (5 rows)
      
      v1 three fields
                                             QUERY PLAN                                        
      -----------------------------------------------------------------------------------------
       Hash Join  (cost=5.09..71.03 rows=309 width=309)
         Hash Cond: (d.form_id = e.form_id)
         ->  Seq Scan on ddd d  (cost=0.00..65.09 rows=309 width=309)
         ->  Hash  (cost=3.84..3.84 rows=100 width=4)
               ->  Index Only Scan using eee_pkey on eee e  (cost=0.14..3.84 rows=100 width=4)
      (5 rows)
      
      v0 complete
                                   QUERY PLAN                              
      ---------------------------------------------------------------------
       Hash Join  (cost=9.25..75.18 rows=309 width=2025)
         Hash Cond: (d.form_id = e.form_id)
         ->  Seq Scan on ddd d  (cost=0.00..65.09 rows=309 width=1521)
         ->  Hash  (cost=8.00..8.00 rows=100 width=508)
               ->  Seq Scan on eee e  (cost=0.00..8.00 rows=100 width=508)
      (5 rows)
      
      v0 three fields
                                             QUERY PLAN                                        
      -----------------------------------------------------------------------------------------
       Hash Join  (cost=5.09..71.03 rows=309 width=309)
         Hash Cond: (d.form_id = e.form_id)
         ->  Seq Scan on ddd d  (cost=0.00..65.09 rows=309 width=309)
         ->  Hash  (cost=3.84..3.84 rows=100 width=4)
               ->  Index Only Scan using eee_pkey on eee e  (cost=0.14..3.84 rows=100 width=4)
      (5 rows)
      
      v0 four fields
                                             QUERY PLAN                                        
      -----------------------------------------------------------------------------------------
       Hash Join  (cost=5.09..71.03 rows=309 width=713)
         Hash Cond: (d.form_id = e.form_id)
         ->  Seq Scan on ddd d  (cost=0.00..65.09 rows=309 width=713)
         ->  Hash  (cost=3.84..3.84 rows=100 width=4)
               ->  Index Only Scan using eee_pkey on eee e  (cost=0.14..3.84 rows=100 width=4)
      (5 rows)
      

      现在看看计划中的“宽度”列:它们不同,不仅取决于表和视图定义,还取决于最终查询。

      这是因为,在 postgres 中,视图是一种宏:它被合并到查询计划中**在*发生任何优化之前。之后的优化器会从计划中删除未引用的列,从而减少结果的行大小。

      从基表读取的数据量当然是相同的:物理表没有改变它们的行大小。

      非内部人士注意:我故意使用CHAR(xxx) 列来扩大行大小。 varchar() 列会被烘烤。 (:=放入辅助存储),并且不会夸大行大小。

      【讨论】:

        猜你喜欢
        • 2023-02-07
        • 2012-01-21
        • 1970-01-01
        • 1970-01-01
        • 2015-06-13
        • 1970-01-01
        • 1970-01-01
        • 2015-09-05
        • 1970-01-01
        相关资源
        最近更新 更多