{"id":12233,"date":"2019-02-05T14:28:42","date_gmt":"2019-02-05T13:28:42","guid":{"rendered":"https:\/\/www.dbi-services.com\/blog\/what-are-custom-and-generic-plans-in-postgresql\/"},"modified":"2019-02-05T14:28:42","modified_gmt":"2019-02-05T13:28:42","slug":"what-are-custom-and-generic-plans-in-postgresql","status":"publish","type":"post","link":"https:\/\/www.dbi-services.com\/blog\/what-are-custom-and-generic-plans-in-postgresql\/","title":{"rendered":"What are custom and generic plans in PostgreSQL?"},"content":{"rendered":"<p>I have already written a post about <a href=\"https:\/\/www.dbi-services.com\/blog\/when-you-execute-the-same-statement-thousands-of-times-prepare-it\/\" target=\"_blank\" rel=\"noopener noreferrer\">prepared statements in PostgreSQL<\/a> some time ago. What I did not mention in that post is the concept of generic and custom plans. So lets have a look at those.<\/p>\n<p><!--more--><\/p>\n<p>As always, we start with creating a demo table and populate that table with some sample data:<\/p>\n<pre class=\"brush: sql; gutter: true; first-line: 1\">\npgbench=# create table demo ( a int, b text );\nCREATE TABLE\npgbench=# insert into demo select i, 'aaa' from generate_series (1,100) i;\nINSERT 0 100\npgbench=# insert into demo select i, 'bbb' from generate_series (101,200) i;\nINSERT 0 100\npgbench=# insert into demo select i, 'ccc' from generate_series (201,300) i;\nINSERT 0 100\npgbench=# analyze demo;\nANALYZE\n<\/pre>\n<p>Now that we have some data we can prepare a statement we would like to execute with various values:<\/p>\n<pre class=\"brush: sql; gutter: true; first-line: 1\">\npgbench=# prepare my_stmt as select * from demo where b = $1;\nPREPARE\n<\/pre>\n<p>Btw: You can check for the currently available prepared statements in your session by querying the <a href=\"https:\/\/www.postgresql.org\/docs\/current\/view-pg-prepared-statements.html\" target=\"_blank\" rel=\"noopener noreferrer\">pg_prepared_statements<\/a> catalog view:<\/p>\n<pre class=\"brush: sql; gutter: true; first-line: 1\">\npgbench=# select * from pg_prepared_statements;\n  name   |                      statement                      |         prepare_time          | parameter_types | from_sql \n---------+-----------------------------------------------------+-------------------------------+-----------------+----------\n my_stmt | prepare my_stmt as select * from demo where b = $1; | 2019-02-05 13:15:39.232521+01 | {text}          | t\n<\/pre>\n<p>When we <a href=\"https:\/\/www.postgresql.org\/docs\/11\/sql-explain.html\" target=\"_blank\" rel=\"noopener noreferrer\">explain(analyze)<\/a> that statement what do we see?<\/p>\n<pre class=\"brush: sql; gutter: true; first-line: 1; highlight: [5]\">\npgbench=# explain (analyze) execute my_stmt ( 'aaa' );\n                                            QUERY PLAN                                            \n--------------------------------------------------------------------------------------------------\n Seq Scan on demo  (cost=0.00..5.75 rows=100 width=8) (actual time=0.111..0.230 rows=100 loops=1)\n   Filter: (b = 'aaa'::text)\n   Rows Removed by Filter: 200\n Planning time: 0.344 ms\n Execution time: 0.285 ms\n(5 rows)\n<\/pre>\n<p>In the &#8220;Filter&#8221; line of the execution plan we can see the real value (&#8216;aaa&#8217;) we passed to our prepared statement. When you see that, it is a so called custom plan. When PostgreSQL goes for a custom plan that means the statement will be re-planned for the provided set of parameters. When you execute that a few times more:<\/p>\n<pre class=\"brush: sql; gutter: true; first-line: 1; highlight: [45]\">\npgbench=# explain (analyze) execute my_stmt ( 'aaa' );\n                                            QUERY PLAN                                            \n--------------------------------------------------------------------------------------------------\n Seq Scan on demo  (cost=0.00..5.75 rows=100 width=8) (actual time=0.045..0.158 rows=100 loops=1)\n   Filter: (b = 'aaa'::text)\n   Rows Removed by Filter: 200\n Planning time: 0.243 ms\n Execution time: 0.225 ms\n(5 rows)\n\npgbench=# explain (analyze) execute my_stmt ( 'aaa' );\n                                            QUERY PLAN                                            \n--------------------------------------------------------------------------------------------------\n Seq Scan on demo  (cost=0.00..5.75 rows=100 width=8) (actual time=0.035..0.123 rows=100 loops=1)\n   Filter: (b = 'aaa'::text)\n   Rows Removed by Filter: 200\n Planning time: 0.416 ms\n Execution time: 0.173 ms\n(5 rows)\n\npgbench=# explain (analyze) execute my_stmt ( 'aaa' );\n                                            QUERY PLAN                                            \n--------------------------------------------------------------------------------------------------\n Seq Scan on demo  (cost=0.00..5.75 rows=100 width=8) (actual time=0.036..0.124 rows=100 loops=1)\n   Filter: (b = 'aaa'::text)\n   Rows Removed by Filter: 200\n Planning time: 0.195 ms\n Execution time: 0.178 ms\n(5 rows)\n\npgbench=# explain (analyze) execute my_stmt ( 'aaa' );\n                                            QUERY PLAN                                            \n--------------------------------------------------------------------------------------------------\n Seq Scan on demo  (cost=0.00..5.75 rows=100 width=8) (actual time=0.035..0.126 rows=100 loops=1)\n   Filter: (b = 'aaa'::text)\n   Rows Removed by Filter: 200\n Planning time: 0.192 ms\n Execution time: 0.224 ms\n(5 rows)\n\npgbench=# explain (analyze) execute my_stmt ( 'aaa' );\n                                            QUERY PLAN                                            \n--------------------------------------------------------------------------------------------------\n Seq Scan on demo  (cost=0.00..5.75 rows=100 width=8) (actual time=0.038..0.130 rows=100 loops=1)\n   Filter: (b = $1)\n   Rows Removed by Filter: 200\n Planning time: 0.191 ms\n Execution time: 0.183 ms\n(5 rows)\n<\/pre>\n<p>&#8230; you will see that the &#8220;Filter&#8221; line changes from displaying the actual parameter to a place holder. Now we have a generic plan. This generic plan will not change anymore for the lifetime of the prepared statement no matter which value you pass into the prepared statement:<\/p>\n<pre class=\"brush: sql; gutter: true; first-line: 1; highlight: [5,15,25]\">\npgbench=# explain (analyze) execute my_stmt ( 'bbb' );\n                                            QUERY PLAN                                            \n--------------------------------------------------------------------------------------------------\n Seq Scan on demo  (cost=0.00..5.75 rows=100 width=8) (actual time=0.096..0.219 rows=100 loops=1)\n   Filter: (b = $1)\n   Rows Removed by Filter: 200\n Planning time: 0.275 ms\n Execution time: 0.352 ms\n(5 rows)\n\npgbench=# explain (analyze) execute my_stmt ( 'ccc' );\n                                            QUERY PLAN                                            \n--------------------------------------------------------------------------------------------------\n Seq Scan on demo  (cost=0.00..5.75 rows=100 width=8) (actual time=0.090..0.132 rows=100 loops=1)\n   Filter: (b = $1)\n   Rows Removed by Filter: 200\n Planning time: 0.084 ms\n Execution time: 0.204 ms\n(5 rows)\n\npgbench=# explain (analyze) execute my_stmt ( null );\n                                           QUERY PLAN                                           \n------------------------------------------------------------------------------------------------\n Seq Scan on demo  (cost=0.00..5.75 rows=100 width=8) (actual time=0.033..0.033 rows=0 loops=1)\n   Filter: (b = $1)\n   Rows Removed by Filter: 300\n Planning time: 0.018 ms\n Execution time: 0.051 ms\n(5 rows)\n<\/pre>\n<p>When you take a look at the source code (src\/backend\/utils\/cache\/plancache.c) you will see why it changes after 5 executions:<\/p>\n<pre class=\"brush: c; gutter: true; first-line: 1; highlight: [29]\">\n\/*\n * choose_custom_plan: choose whether to use custom or generic plan\n *\n * This defines the policy followed by GetCachedPlan.\n *\/\nstatic bool\nchoose_custom_plan(CachedPlanSource *plansource, ParamListInfo boundParams)\n{\n        double          avg_custom_cost;\n\n        \/* One-shot plans will always be considered custom *\/\n        if (plansource-&gt;is_oneshot)\n                return true;\n\n        \/* Otherwise, never any point in a custom plan if there's no parameters *\/\n        if (boundParams == NULL)\n                return false;\n        \/* ... nor for transaction control statements *\/\n        if (IsTransactionStmtPlan(plansource))\n                return false;\n\n        \/* See if caller wants to force the decision *\/\n        if (plansource-&gt;cursor_options &amp; CURSOR_OPT_GENERIC_PLAN)\n                return false;\n        if (plansource-&gt;cursor_options &amp; CURSOR_OPT_CUSTOM_PLAN)\n                return true;\n\n        \/* Generate custom plans until we have done at least 5 (arbitrary) *\/\n        if (plansource-&gt;num_custom_plans &lt; 5)\n                return true;\n<\/pre>\n<p>Even if we change the data and analyze the table again we will still get a generic plan once PostgreSQL went for it:<\/p>\n<pre class=\"brush: c; gutter: true; first-line: 1; highlight: [18]\">\npgbench=# insert into demo select i, 'ddd' from generate_series (201,210) i;\nINSERT 0 10\npgbench=# insert into demo select i, 'ee' from generate_series (211,211) i;\nINSERT 0 1\npgbench=# analyze demo;\nANALYZE\npgbench=# select b,count(*) from demo group by b order by b;\n  b  | count \n-----+-------\n aaa |   100\n bbb |   100\n ccc |   100\n ddd |    10\n ee  |     1\n(5 rows)\n\npgbench=# explain (analyze) execute my_stmt ( 'ddd' );\n                                           QUERY PLAN                                           \n------------------------------------------------------------------------------------------------\n Seq Scan on demo  (cost=0.00..5.88 rows=78 width=8) (actual time=0.147..0.151 rows=10 loops=1)\n   Filter: (b = $1)\n   Rows Removed by Filter: 300\n Planning time: 0.293 ms\n Execution time: 0.190 ms\n(5 rows)\n<\/pre>\n<p>The situation changes when we have much more data, data is not uniformly distributed and we have an index on the column &#8220;b&#8221;:<\/p>\n<pre class=\"brush: sql; gutter: true; first-line: 1\">\npgbench=# truncate demo;\nTRUNCATE TABLE\npgbench=# insert into demo select i, 'aaa' from generate_series (1,1000000) i;\nINSERT 0 1000000\npgbench=# insert into demo select i, 'bbb' from generate_series (1000001,2000000) i;\nINSERT 0 1000000\npgbench=# insert into demo select i, 'ccc' from generate_series (2000001,3000000) i;\nINSERT 0 1000000\npgbench=# insert into demo select i, 'eee' from generate_series (3000001,3000010) i;\nINSERT 0 10\npgbench=# create index i1 on demo (b);\nCREATE INDEX\npgbench=# select b,count(*) from demo group by b order by b;\n  b  |  count  \n-----+---------\n aaa | 1000000\n bbb | 1000000\n ccc | 1000000\n eee |      10\n(4 rows)\n\npgbench=# prepare my_stmt as select * from demo where b = $1;\nPREPARE\n<\/pre>\n<p>No matter how often we execute the following statement (which asks for &#8216;eee&#8217;), we never get a generic plan:<\/p>\n<pre class=\"brush: sql; gutter: true; first-line: 1\">\npgbench=# explain (analyze) execute my_stmt ('eee');\n                                                QUERY PLAN                                                \n----------------------------------------------------------------------------------------------------------\n Index Scan using i1 on demo  (cost=0.43..4.45 rows=1 width=8) (actual time=0.054..0.061 rows=10 loops=1)\n   Index Cond: (b = 'eee'::text)\n Planning time: 0.249 ms\n Execution time: 0.106 ms\n(4 rows)\n\n-----&gt; REPEAT THAT HOW OFTEN YOU WANT BUT AT LEAST 10 TIMES\n\npgbench=# explain (analyze) execute my_stmt ('eee');\n                                                QUERY PLAN                                                \n----------------------------------------------------------------------------------------------------------\n Index Scan using i1 on demo  (cost=0.43..4.45 rows=1 width=8) (actual time=0.054..0.061 rows=10 loops=1)\n   Index Cond: (b = 'eee'::text)\n Planning time: 0.249 ms\n Execution time: 0.106 ms\n<\/pre>\n<p>This is because the custom plan (which includes the costs for re-planning) is always cheaper than the generic plan (which does not include the costs for re-planning) when we have a data distribution like that. The documentation is very clear about that: <a href=\"https:\/\/www.postgresql.org\/docs\/current\/sql-prepare.html\" target=\"_blank\" rel=\"noopener noreferrer\">&#8220;Using EXECUTE values which are rare in columns with many duplicates can generate custom plans that are so much cheaper than the generic plan, even after adding planning overhead, that the generic plan might never be used&#8221;<\/a>. <\/p>\n<p>Hope that helps.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I have already written a post about prepared statements in PostgreSQL some time ago. What I did not mention in that post is the concept of generic and custom plans. So lets have a look at those.<\/p>\n","protected":false},"author":29,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[229],"tags":[77],"type_dbi":[],"class_list":["post-12233","post","type-post","status-publish","format-standard","hentry","category-database-administration-monitoring","tag-postgresql"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v27.2 (Yoast SEO v27.4) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>What are custom and generic plans in PostgreSQL? - dbi Blog<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.dbi-services.com\/blog\/what-are-custom-and-generic-plans-in-postgresql\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"What are custom and generic plans in PostgreSQL?\" \/>\n<meta property=\"og:description\" content=\"I have already written a post about prepared statements in PostgreSQL some time ago. What I did not mention in that post is the concept of generic and custom plans. So lets have a look at those.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.dbi-services.com\/blog\/what-are-custom-and-generic-plans-in-postgresql\/\" \/>\n<meta property=\"og:site_name\" content=\"dbi Blog\" \/>\n<meta property=\"article:published_time\" content=\"2019-02-05T13:28:42+00:00\" \/>\n<meta name=\"author\" content=\"Daniel Westermann\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@westermanndanie\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Daniel Westermann\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"6 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/what-are-custom-and-generic-plans-in-postgresql\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/what-are-custom-and-generic-plans-in-postgresql\\\/\"},\"author\":{\"name\":\"Daniel Westermann\",\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/#\\\/schema\\\/person\\\/8d08e9bd996a89bd75c0286cbabf3c66\"},\"headline\":\"What are custom and generic plans in PostgreSQL?\",\"datePublished\":\"2019-02-05T13:28:42+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/what-are-custom-and-generic-plans-in-postgresql\\\/\"},\"wordCount\":389,\"commentCount\":0,\"keywords\":[\"PostgreSQL\"],\"articleSection\":[\"Database Administration &amp; Monitoring\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/what-are-custom-and-generic-plans-in-postgresql\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/what-are-custom-and-generic-plans-in-postgresql\\\/\",\"url\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/what-are-custom-and-generic-plans-in-postgresql\\\/\",\"name\":\"What are custom and generic plans in PostgreSQL? - dbi Blog\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/#website\"},\"datePublished\":\"2019-02-05T13:28:42+00:00\",\"author\":{\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/#\\\/schema\\\/person\\\/8d08e9bd996a89bd75c0286cbabf3c66\"},\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/what-are-custom-and-generic-plans-in-postgresql\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/what-are-custom-and-generic-plans-in-postgresql\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/what-are-custom-and-generic-plans-in-postgresql\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Accueil\",\"item\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"What are custom and generic plans in PostgreSQL?\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/\",\"name\":\"dbi Blog\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/#\\\/schema\\\/person\\\/8d08e9bd996a89bd75c0286cbabf3c66\",\"name\":\"Daniel Westermann\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/31350ceeecb1dd8986339a29bf040d4cd3cd087d410deccd8f55234466d6c317?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/31350ceeecb1dd8986339a29bf040d4cd3cd087d410deccd8f55234466d6c317?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/31350ceeecb1dd8986339a29bf040d4cd3cd087d410deccd8f55234466d6c317?s=96&d=mm&r=g\",\"caption\":\"Daniel Westermann\"},\"description\":\"Daniel Westermann is Principal Consultant and Technology Leader Open Infrastructure at dbi services. He has more than 15 years of experience in management, engineering and optimization of databases and infrastructures, especially on Oracle and PostgreSQL. Since the beginning of his career, he has specialized in Oracle Technologies and is Oracle Certified Professional 12c and Oracle Certified Expert RAC\\\/GridInfra. Over time, Daniel has become increasingly interested in open source technologies, becoming \u201cTechnology Leader Open Infrastructure\u201d and PostgreSQL expert. \u00a0Based on community or EnterpriseDB tools, he develops and installs complex high available solutions with PostgreSQL. He is also a certified PostgreSQL Plus 9.0 Professional and a Postgres Advanced Server 9.4 Professional. He is a regular speaker at PostgreSQL conferences in Switzerland and Europe. Today Daniel is also supporting our customers on AWS services such as AWS RDS, database migrations into the cloud, EC2 and automated infrastructure management with AWS SSM (System Manager). He is a certified AWS Solutions Architect Professional. Prior to dbi services, Daniel was Management System Engineer at LC SYSTEMS-Engineering AG in Basel. Before that, he worked as Oracle Developper &amp;\u00a0Project Manager at Delta Energy Solutions AG in Basel (today Powel AG). Daniel holds a diploma in Business Informatics (DHBW, Germany). His branch-related experience mainly covers the pharma industry, the financial sector, energy, lottery and telecommunications.\",\"sameAs\":[\"https:\\\/\\\/x.com\\\/westermanndanie\"],\"url\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/author\\\/daniel-westermann\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"What are custom and generic plans in PostgreSQL? - dbi Blog","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.dbi-services.com\/blog\/what-are-custom-and-generic-plans-in-postgresql\/","og_locale":"en_US","og_type":"article","og_title":"What are custom and generic plans in PostgreSQL?","og_description":"I have already written a post about prepared statements in PostgreSQL some time ago. What I did not mention in that post is the concept of generic and custom plans. So lets have a look at those.","og_url":"https:\/\/www.dbi-services.com\/blog\/what-are-custom-and-generic-plans-in-postgresql\/","og_site_name":"dbi Blog","article_published_time":"2019-02-05T13:28:42+00:00","author":"Daniel Westermann","twitter_card":"summary_large_image","twitter_creator":"@westermanndanie","twitter_misc":{"Written by":"Daniel Westermann","Est. reading time":"6 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.dbi-services.com\/blog\/what-are-custom-and-generic-plans-in-postgresql\/#article","isPartOf":{"@id":"https:\/\/www.dbi-services.com\/blog\/what-are-custom-and-generic-plans-in-postgresql\/"},"author":{"name":"Daniel Westermann","@id":"https:\/\/www.dbi-services.com\/blog\/#\/schema\/person\/8d08e9bd996a89bd75c0286cbabf3c66"},"headline":"What are custom and generic plans in PostgreSQL?","datePublished":"2019-02-05T13:28:42+00:00","mainEntityOfPage":{"@id":"https:\/\/www.dbi-services.com\/blog\/what-are-custom-and-generic-plans-in-postgresql\/"},"wordCount":389,"commentCount":0,"keywords":["PostgreSQL"],"articleSection":["Database Administration &amp; Monitoring"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.dbi-services.com\/blog\/what-are-custom-and-generic-plans-in-postgresql\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.dbi-services.com\/blog\/what-are-custom-and-generic-plans-in-postgresql\/","url":"https:\/\/www.dbi-services.com\/blog\/what-are-custom-and-generic-plans-in-postgresql\/","name":"What are custom and generic plans in PostgreSQL? - dbi Blog","isPartOf":{"@id":"https:\/\/www.dbi-services.com\/blog\/#website"},"datePublished":"2019-02-05T13:28:42+00:00","author":{"@id":"https:\/\/www.dbi-services.com\/blog\/#\/schema\/person\/8d08e9bd996a89bd75c0286cbabf3c66"},"breadcrumb":{"@id":"https:\/\/www.dbi-services.com\/blog\/what-are-custom-and-generic-plans-in-postgresql\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.dbi-services.com\/blog\/what-are-custom-and-generic-plans-in-postgresql\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.dbi-services.com\/blog\/what-are-custom-and-generic-plans-in-postgresql\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Accueil","item":"https:\/\/www.dbi-services.com\/blog\/"},{"@type":"ListItem","position":2,"name":"What are custom and generic plans in PostgreSQL?"}]},{"@type":"WebSite","@id":"https:\/\/www.dbi-services.com\/blog\/#website","url":"https:\/\/www.dbi-services.com\/blog\/","name":"dbi Blog","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.dbi-services.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/www.dbi-services.com\/blog\/#\/schema\/person\/8d08e9bd996a89bd75c0286cbabf3c66","name":"Daniel Westermann","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/31350ceeecb1dd8986339a29bf040d4cd3cd087d410deccd8f55234466d6c317?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/31350ceeecb1dd8986339a29bf040d4cd3cd087d410deccd8f55234466d6c317?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/31350ceeecb1dd8986339a29bf040d4cd3cd087d410deccd8f55234466d6c317?s=96&d=mm&r=g","caption":"Daniel Westermann"},"description":"Daniel Westermann is Principal Consultant and Technology Leader Open Infrastructure at dbi services. He has more than 15 years of experience in management, engineering and optimization of databases and infrastructures, especially on Oracle and PostgreSQL. Since the beginning of his career, he has specialized in Oracle Technologies and is Oracle Certified Professional 12c and Oracle Certified Expert RAC\/GridInfra. Over time, Daniel has become increasingly interested in open source technologies, becoming \u201cTechnology Leader Open Infrastructure\u201d and PostgreSQL expert. \u00a0Based on community or EnterpriseDB tools, he develops and installs complex high available solutions with PostgreSQL. He is also a certified PostgreSQL Plus 9.0 Professional and a Postgres Advanced Server 9.4 Professional. He is a regular speaker at PostgreSQL conferences in Switzerland and Europe. Today Daniel is also supporting our customers on AWS services such as AWS RDS, database migrations into the cloud, EC2 and automated infrastructure management with AWS SSM (System Manager). He is a certified AWS Solutions Architect Professional. Prior to dbi services, Daniel was Management System Engineer at LC SYSTEMS-Engineering AG in Basel. Before that, he worked as Oracle Developper &amp;\u00a0Project Manager at Delta Energy Solutions AG in Basel (today Powel AG). Daniel holds a diploma in Business Informatics (DHBW, Germany). His branch-related experience mainly covers the pharma industry, the financial sector, energy, lottery and telecommunications.","sameAs":["https:\/\/x.com\/westermanndanie"],"url":"https:\/\/www.dbi-services.com\/blog\/author\/daniel-westermann\/"}]}},"_links":{"self":[{"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/posts\/12233","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/users\/29"}],"replies":[{"embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/comments?post=12233"}],"version-history":[{"count":0,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/posts\/12233\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/media?parent=12233"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/categories?post=12233"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/tags?post=12233"},{"taxonomy":"type","embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/type_dbi?post=12233"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}