From 61677219e197e71ed1a487a4dd6c2e46cdc47fd2 Mon Sep 17 00:00:00 2001
From: "dgrowley@gmail.com" <dgrowley@gmail.com>
Date: Wed, 31 Oct 2018 01:45:41 +1300
Subject: [PATCH v5] Add documentation section appendix detailing some
 limitations of PostgreSQL

---
 doc/src/sgml/filelist.sgml |   1 +
 doc/src/sgml/limits.sgml   | 128 +++++++++++++++++++++++++++++++++++++++++++++
 doc/src/sgml/postgres.sgml |   1 +
 3 files changed, 130 insertions(+)
 create mode 100644 doc/src/sgml/limits.sgml

diff --git a/doc/src/sgml/filelist.sgml b/doc/src/sgml/filelist.sgml
index 48ac14a838..0cf8960b8b 100644
--- a/doc/src/sgml/filelist.sgml
+++ b/doc/src/sgml/filelist.sgml
@@ -184,6 +184,7 @@
 <!ENTITY release-7.4    SYSTEM "release-7.4.sgml">
 <!ENTITY release-old    SYSTEM "release-old.sgml">
 
+<!ENTITY limits     SYSTEM "limits.sgml">
 <!ENTITY acronyms   SYSTEM "acronyms.sgml">
 
 <!ENTITY features-supported   SYSTEM "features-supported.sgml">
diff --git a/doc/src/sgml/limits.sgml b/doc/src/sgml/limits.sgml
new file mode 100644
index 0000000000..09b7348092
--- /dev/null
+++ b/doc/src/sgml/limits.sgml
@@ -0,0 +1,128 @@
+<!-- doc/src/sgml/limits.sgml -->
+
+<appendix id="limits">
+ <title><productname>PostgreSQL</productname> Limitations</title>
+
+ <para>
+  Practical limits, such as performance limitations or available disk space
+  may apply before absolute hard limits are reached.  However, with those
+  aside, the following table describes the hard limits of
+  <productname>PostgreSQL</productname>.
+ </para>
+
+<table id="limits-table">
+ <title><productname>PostgreSQL</productname> limitations</title>
+ <tgroup cols="3">
+  <thead>
+   <row>
+    <entry>Item</entry>
+    <entry>Upper Limit</entry>
+    <entry>Comment</entry>
+   </row>
+  </thead>
+
+  <tbody>
+   <row>
+    <entry>Database size</entry>
+    <entry>Unlimited</entry>
+    <entry></entry>
+   </row>
+
+   <row>
+    <entry>Number of databases</entry>
+    <!-- 2^32 - FirstNormalObjectId - 1 -->
+    <entry>4,294,950,911</entry>
+    <entry></entry>
+   </row>
+
+   <row>
+    <entry>Relations per database</entry>
+    <!-- (2^32 - FirstNormalObjectId - 1) / 3 (3 because of the table and the
+    two types that are created to go with it) -->
+    <entry>1,431,650,303</entry>
+    <entry></entry>
+   </row>
+
+   <row>
+    <entry>Relation size</entry>
+    <entry>32 TB</entry>
+    <entry>Assuming the default BLCKSZ of 8192 bytes</entry>
+   </row>
+
+   <row>
+    <entry>Rows per table</entry>
+    <entry>Limited by the number of tuples that can fit onto 4,294,967,295 pages</entry>
+    <entry></entry>
+   </row>
+
+   <row>
+    <entry>Columns per table</entry>
+    <entry>1600</entry>
+    <entry>Further limited by tuple size fitting on a single page. See note
+    below</entry>
+   </row>
+
+   <row>
+    <entry>Field size</entry>
+    <entry>1 GB</entry>
+    <entry></entry>
+   </row>
+
+   <row>
+    <entry>Identifier length</entry>
+    <entry>63 bytes</entry>
+    <entry>Can be increased by recompiling
+    <productname>PostgreSQL</productname></entry>
+   </row>
+
+   <row>
+    <entry>Indexes per table</entry>
+    <entry>Unlimited</entry>
+    <entry>Constrained by maximum relations per database</entry>
+   </row>
+
+   <row>
+    <entry>Columns per index</entry>
+    <entry>32</entry>
+    <entry>Can be increased by recompiling
+    <productname>PostgreSQL</productname></entry>
+   </row>
+
+   <row>
+    <entry>Partition keys</entry>
+    <entry>32</entry>
+    <entry>Can be increased by recompiling
+    <productname>PostgreSQL</productname></entry>
+   </row>
+  </tbody>
+ </tgroup>
+</table>
+
+  <note>
+    <para>
+     The maximum number of columns for a table is further reduced as the tuple
+     being stored must fit on a single heap page.  Variable length fields such
+     as <literal>TEXT</literal>, <literal>VARCHAR</literal> and
+     <literal>CHAR</literal> can have their values stored out of line in the
+     table's TOAST table when the values are large enough to require it.  Only
+     an 18 byte pointer must remain inside the tuple in the table's heap.  For
+     shorter length variable length fields either a 4 byte or 1 byte field
+     header is used, and the value is stored inside the heap tuple.  Often
+     this can mean the actual maximum number of columns that you can store
+     inside a table is further reduced as the tuple can become too large to
+     fit inside a single 8192 byte heap page.  For example, excluding the
+     tuple header, a tuple made up of 1600 <literal>INT</literal> columns
+     would consume 6400 bytes and could be stored in a heap page, but a tuple
+     of 1600 <literal>BIGINT</literal> columns would consume 12800 bytes,
+     therefore not fit inside a heap page.
+    </para>
+
+    <para>
+     Columns which have been dropped from the table also contribute to the
+     maximum column limit, although the dropped column values for newly
+     created tuples are internally marked as NULL in the tuple's null bitmap,
+     which does occupy space.
+    </para>
+  </note>
+
+</appendix>
diff --git a/doc/src/sgml/postgres.sgml b/doc/src/sgml/postgres.sgml
index 0070603fc3..2fe6f9ca42 100644
--- a/doc/src/sgml/postgres.sgml
+++ b/doc/src/sgml/postgres.sgml
@@ -276,6 +276,7 @@
   &external-projects;
   &sourcerepo;
   &docguide;
+  &limits;
   &acronyms;
 
  </part>
-- 
2.16.2.windows.1

