暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

PostgreSQL的 heap-only-tuples特性第三部分

飞象数据 2019-01-04
498

这一系列文章将以11版本的新特性作为焦点。在开发这个版本的过程中,一个特性引起了我的注意。它可以在发行说明中找到。

当表达式的值不变时,允许对表达式索引进行heap-only-tuple (HOT)更新(Konstantin Knizhnik)。

这个特性需要一些关于PostgreSQL如何工作的知识,我将通过三篇文章来解释:

  1. MVCC如何工作的和更新heap-only-tuples。

  2. 什么时候PostgreSQL不使用heap-only-tuples更新和v11中新特性的介绍。

  3. 对性能的影响。

这个特性在11.1版本中被禁用,因为它可能导致实例崩溃。之所以选择发表这些文章,是因为它们有助于理解HOT更新的机制以及这个特性可能带来的好处。

1、  对性能的影响

这里有一个简单的测试来展示这个特性的好处。因为PostgreSQL避免了更新索引,我们可以预期性能的增加,并且在索引大小方面,就像上面说的一样,避免了碎片化:

  1. CREATE TABLE t5 (c1 jsonb, c2 int,c3 int);

  2. CREATE INDEX ON t5 ((c1->>'prenom')) ;

  3. CREATE INDEX ON t5 (c2);

  4. INSERT INTO t5 VALUES ('{ "prenom":"adrien" , "valeur" : "1"}'::jsonb,1,1);

  5. INSERT INTO t5 VALUES ('{ "prenom":"guillaume" , "valeur" : "2"}'::jsonb,2,2);

  6. \dt+ t5

  7.                   List of relations

  8. Schema | Name | Type  |  Owner   | Size  | Description

  9. --------+------+-------+----------+-------+-------------

  10. public | t5   | table | postgres | 16 kB |

  11. (1 row)

  12. \di+ t5*

  13.                           List of relations

  14. Schema |    Name     | Type  |  Owner   | Table | Size  | Description

  15. --------+-------------+-------+----------+-------+-------+-------------

  16. public | t5_c2_idx   | index | postgres | t5    | 16 kB |

  17. public | t5_expr_idx | index | postgres | t5    | 16 kB |

  18. (2 rows)

复制

看一下pgbench的测试脚本:

  1. \set id  random(1, 100000)

  2. \set id2  random(1, 100000)

  3. UPDATE t5 SET c1 = '{"valeur": ":id", "prenom": "guillaume"}' WHERE c2=2;

  4. UPDATE t5 SET c1 = '{"valeur": ":id2", "prenom": "adrien"}' WHERE c2=1;

复制

然后设置 recheck_on_update=on (默认),执行120秒:

  1. pgbench -f test.sql -n -c6 -T 120

  2. transaction type: test.sql

  3. scaling factor: 1

  4. query mode: simple

  5. number of clients: 6

  6. number of threads: 1

  7. duration: 120 s

  8. number of transactions actually processed: 2743163

  9. latency average = 0.262 ms

  10. tps = 22859.646914 (including connections establishing)

  11. tps = 22859.938191 (excluding connections establishing)

  12. \dt+ t5*

  13.                    List of relations

  14. Schema | Name | Type  |  Owner   |  Size  | Description

  15. --------+------+-------+----------+--------+-------------

  16. public | t5   | table | postgres | 376 kB |

  17. (1 row)

  18. \di+ t5*

  19.                           List of relations

  20. Schema |    Name     | Type  |  Owner   | Table | Size  | Description

  21. --------+-------------+-------+----------+-------+-------+-------------

  22. public | t5_c2_idx   | index | postgres | t5    | 16 kB |

  23. public | t5_expr_idx | index | postgres | t5    | 32 kB |

  24. (2 rows)

  25. SELECT * from pg_stat_user_tables where relname = 't5';

  26. -[ RECORD 1 ]-------+------------------------------

  27. relid               | 8890622

  28. schemaname          | public

  29. relname             | t5

  30. seq_scan            | 4

  31. seq_tup_read        | 0

  32. idx_scan            | 7999055

  33. idx_tup_fetch       | 7999055

  34. n_tup_ins           | 4

  35. n_tup_upd           | 7999055

  36. n_tup_del           | 0

  37. n_tup_hot_upd       | 7998236

  38. n_live_tup          | 2

  39. n_dead_tup          | 0

  40. n_mod_since_analyze | 0

  41. last_vacuum         |

  42. last_autovacuum     | 2018-09-19 06:29:37.690575+00

  43. last_analyze        |

  44. last_autoanalyze    | 2018-09-19 06:29:37.719911+00

  45. vacuum_count        | 0

  46. autovacuum_count    | 5

  47. analyze_count       | 0

  48. autoanalyze_count   | 5

复制

现在设置recheck_on_update=off,为什么数据集和以前一样但是这次索引是用这个顺序创建的 : CREATE INDEX ON t5 ((c1->>'prenom')) WITH (recheck_on_update=off);

  1. pgbench -f test.sql -n -c6 -T 120

  2. transaction type: test.sql

  3. scaling factor: 1

  4. query mode: simple

  5. number of clients: 6

  6. number of threads: 1

  7. duration: 120 s

  8. number of transactions actually processed: 1065688

  9. latency average = 0.676 ms

  10. tps = 8880.679565 (including connections establishing)

  11. tps = 8880.796478 (excluding connections establishing)

  12. \dt+ t5

  13.                    List of relations

  14. Schema | Name | Type  |  Owner   |  Size   | Description

  15. --------+------+-------+----------+---------+-------------

  16. public | t5   | table | postgres | 9496 kB |

  17. (1 row)

  18. \di+ t5*

  19.                           List of relations

  20. Schema |    Name     | Type  |  Owner   | Table |  Size  | Description

  21. --------+-------------+-------+----------+-------+--------+-------------

  22. public | t5_c2_idx   | index | postgres | t5    | 768 kB |

  23. public | t5_expr_idx | index | postgres | t5    | 58 MB  |

  24. (2 rows)

  25. select * from pg_stat_user_tables where relname = 't5';

  26. -[ RECORD 1 ]-------+------------------------------

  27. relid               | 8890635

  28. schemaname          | public

  29. relname             | t5

  30. seq_scan            | 2

  31. seq_tup_read        | 0

  32. idx_scan            | 2131376

  33. idx_tup_fetch       | 2131376

  34. n_tup_ins           | 2

  35. n_tup_upd           | 2131376

  36. n_tup_del           | 0

  37. n_tup_hot_upd       | 19

  38. n_live_tup          | 2

  39. n_dead_tup          | 0

  40. n_mod_since_analyze | 0

  41. last_vacuum         |

  42. last_autovacuum     | 2018-09-19 06:34:42.045905+00

  43. last_analyze        |

  44. last_autoanalyze    | 2018-09-19 06:34:42.251183+00

  45. vacuum_count        | 0

  46. autovacuum_count    | 3

  47. analyze_count       | 0

  48. autoanalyze_count   | 3

复制

测试结果:

recheck_on_updateonoffGain
TPS228598880157%
t5 size376 kB9496 kB-96%
t5_c2_idx size16 kB768 kB-98%
t5_expr_idx size32 kB58 MB-99.9%

性能的差异是非常大的,以及表和索引的大小。

禁用autovacuum后重复做第一个测试的结果:

  1. pgbench -f test.sql -n -c6 -T 120

  2. transaction type: test.sql

  3. scaling factor: 1

  4. query mode: simple

  5. number of clients: 6

  6. number of threads: 1

  7. duration: 120 s

  8. number of transactions actually processed: 2752479

  9. latency average = 0.262 ms

  10. tps = 22937.271749 (including connections establishing)

  11. tps = 22937.545872 (excluding connections establishing)

  12. select * from pg_stat_user_tables where relname = 't5';

  13. -[ RECORD 1 ]-------+--------

  14. relid               | 8890643

  15. schemaname          | public

  16. relname             | t5

  17. seq_scan            | 2

  18. seq_tup_read        | 0

  19. idx_scan            | 5504958

  20. idx_tup_fetch       | 5504958

  21. n_tup_ins           | 2

  22. n_tup_upd           | 5504958

  23. n_tup_del           | 0

  24. n_tup_hot_upd       | 5504258

  25. n_live_tup          | 2

  26. n_dead_tup          | 2416

  27. n_mod_since_analyze | 5504960

  28. last_vacuum         |

  29. last_autovacuum     |

  30. last_analyze        |

  31. last_autoanalyze    |

  32. vacuum_count        | 0

  33. autovacuum_count    | 0

  34. analyze_count       | 0

  35. autoanalyze_count   | 0

  36. \di+ t5*

  37. List of relations

  38. -[ RECORD 1 ]------------

  39. Schema      | public

  40. Name        | t5_c2_idx

  41. Type        | index

  42. Owner       | postgres

  43. Table       | t5

  44. Size        | 16 kB

  45. Description |

  46. -[ RECORD 2 ]------------

  47. Schema      | public

  48. Name        | t5_expr_idx

  49. Type        | index

  50. Owner       | postgres

  51. Table       | t5

  52. Size        | 40 kB

  53. Description |

  54. \dt+ t5

  55. List of relations

  56. -[ RECORD 1 ]---------

  57. Schema      | public

  58. Name        | t5

  59. Type        | table

  60. Owner       | postgres

  61. Size        | 1080 kB

  62. Description |

复制

然后做第二个测试:

  1. pgbench -f test.sql -n -c6 -T 120

  2. transaction type: test.sql

  3. scaling factor: 1

  4. query mode: simple

  5. number of clients: 6

  6. number of threads: 1

  7. duration: 120 s

  8. number of transactions actually processed: 881434

  9. latency average = 0.817 ms

  10. tps = 7345.208875 (including connections establishing)

  11. tps = 7345.304797 (excluding connections establishing)

  12. select * from pg_stat_user_tables where relname = 't5';

  13. -[ RECORD 1 ]-------+--------

  14. relid               | 8890651

  15. schemaname          | public

  16. relname             | t5

  17. seq_scan            | 2

  18. seq_tup_read        | 0

  19. idx_scan            | 1762868

  20. idx_tup_fetch       | 1762868

  21. n_tup_ins           | 2

  22. n_tup_upd           | 1762868

  23. n_tup_del           | 0

  24. n_tup_hot_upd       | 23

  25. n_live_tup          | 2

  26. n_dead_tup          | 1762845

  27. n_mod_since_analyze | 1762870

  28. last_vacuum         |

  29. last_autovacuum     |

  30. last_analyze        |

  31. last_autoanalyze    |

  32. vacuum_count        | 0

  33. autovacuum_count    | 0

  34. analyze_count       | 0

  35. autoanalyze_count   | 0

  36. \di+ t5*

  37. List of relations

  38. -[ RECORD 1 ]------------

  39. Schema      | public

  40. Name        | t5_c2_idx

  41. Type        | index

  42. Owner       | postgres

  43. Table       | t5

  44. Size        | 600 kB

  45. Description |

  46. -[ RECORD 2 ]------------

  47. Schema      | public

  48. Name        | t5_expr_idx

  49. Type        | index

  50. Owner       | postgres

  51. Table       | t5

  52. Size        | 56 MB

  53. Description |

  54. \dt+ t5*

  55. List of relations

  56. -[ RECORD 1 ]---------

  57. Schema      | public

  58. Name        | t5

  59. Type        | table

  60. Owner       | postgres

  61. Size        | 55 MB

  62. Description |

复制

测试结果:

recheck_on_updateonoffGain
TPS229377345212%
t5 size1080 kB55 MB-98%
t5_c2_idx size16 kB600 kB-97%
t5_expr_idx size40 kB56 MB-99.9%

这一次,性能差距是显著的,正如表和索引大小一样,我们还注意到autovacuum的重要性。

为什么我们在索引和表上有这么大的差异?

对于索引来说,这是由于上面解释的机制。PostgreSQL能通过链接这些记录避免更新索引。索引大小不过是轻微的增加,这或许是发生在PostgreSQL不能用HOT机制的地方。例如数据块中没有更多的空间了。

至于表的大小,在打开autovacuum的测试过程中,当HOT机制是禁用的,autovacuum的执行有更大的困难,索引的增长,意味着需要清理的更多。在关闭autovacuum的测试过程中, 差异可以用一个简单的SELECT就可以彻底的更新指针来解释。

请记住,该特性在版本11.1中已经被删除。这些文章是在11.0版本发布后不久后写的,发布它们是为了更好的解释HOT是如何工作的。希望这个特性在将来的版本中是固定的。

2、  原文链接

https://blog.anayrat.info/en/2018/11/26/postgresql-and-heap-only-tuples-updates-part-3/

敬请关注飞象数据

文章转载自飞象数据,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论