1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-13 07:41:39 +03:00

doc, intagg: fix one-to-many mention to many-to-many

Reported-by: Christophe Courtois

Discussion: https://postgr.es/m/aa7cfd73-0d8d-596a-b684-39faa479afa5@dalibo.com

Author: Christophe Courtois

Backpatch-through: master
This commit is contained in:
Bruce Momjian
2023-12-07 19:36:52 -05:00
parent 719b342d36
commit 651030a3d7

View File

@ -54,20 +54,22 @@
<title>Sample Uses</title> <title>Sample Uses</title>
<para> <para>
Many database systems have the notion of a one to many table. Such a table Many database systems have the notion of a many to many table. Such a table
usually sits between two indexed tables, for example: usually sits between two indexed tables, for example:
<programlisting> <programlisting>
CREATE TABLE left (id INT PRIMARY KEY, ...); CREATE TABLE left_table (id INT PRIMARY KEY, ...);
CREATE TABLE right (id INT PRIMARY KEY, ...); CREATE TABLE right_table (id INT PRIMARY KEY, ...);
CREATE TABLE one_to_many(left INT REFERENCES left, right INT REFERENCES right); CREATE TABLE many_to_many(id_left INT REFERENCES left_table,
id_right INT REFERENCES right_table);
</programlisting> </programlisting>
It is typically used like this: It is typically used like this:
<programlisting> <programlisting>
SELECT right.* from right JOIN one_to_many ON (right.id = one_to_many.right) SELECT right_table.*
WHERE one_to_many.left = <replaceable>item</replaceable>; FROM right_table JOIN many_to_many ON (right_table.id = many_to_many.id_right)
WHERE many_to_many.id_left = <replaceable>item</replaceable>;
</programlisting> </programlisting>
This will return all the items in the right hand table for an entry This will return all the items in the right hand table for an entry
@ -76,7 +78,7 @@ SELECT right.* from right JOIN one_to_many ON (right.id = one_to_many.right)
<para> <para>
Now, this methodology can be cumbersome with a very large number of Now, this methodology can be cumbersome with a very large number of
entries in the <structname>one_to_many</structname> table. Often, entries in the <structname>many_to_many</structname> table. Often,
a join like this would result in an index scan a join like this would result in an index scan
and a fetch for each right hand entry in the table for a particular and a fetch for each right hand entry in the table for a particular
left hand entry. If you have a very dynamic system, there is not much you left hand entry. If you have a very dynamic system, there is not much you
@ -85,9 +87,9 @@ SELECT right.* from right JOIN one_to_many ON (right.id = one_to_many.right)
<programlisting> <programlisting>
CREATE TABLE summary AS CREATE TABLE summary AS
SELECT left, int_array_aggregate(right) AS right SELECT id_left, int_array_aggregate(id_right) AS rights
FROM one_to_many FROM many_to_many
GROUP BY left; GROUP BY id_left;
</programlisting> </programlisting>
This will create a table with one row per left item, and an array This will create a table with one row per left item, and an array
@ -95,33 +97,35 @@ CREATE TABLE summary AS
the array; that's why there is an array enumerator. You can do the array; that's why there is an array enumerator. You can do
<programlisting> <programlisting>
SELECT left, int_array_enum(right) FROM summary WHERE left = <replaceable>item</replaceable>; SELECT id_left, int_array_enum(rights) FROM summary WHERE id_left = <replaceable>item</replaceable>;
</programlisting> </programlisting>
The above query using <function>int_array_enum</function> produces the same results The above query using <function>int_array_enum</function> produces the same results
as as
<programlisting> <programlisting>
SELECT left, right FROM one_to_many WHERE left = <replaceable>item</replaceable>; SELECT id_left, id_right FROM many_to_many WHERE id_left = <replaceable>item</replaceable>;
</programlisting> </programlisting>
The difference is that the query against the summary table has to get The difference is that the query against the summary table has to get
only one row from the table, whereas the direct query against only one row from the table, whereas the direct query against
<structname>one_to_many</structname> must index scan and fetch a row for each entry. <structname>many_to_many</structname> must index scan and fetch a row for each entry.
</para> </para>
<para> <para>
On one system, an <command>EXPLAIN</command> showed a query with a cost of 8488 was On one system, an <command>EXPLAIN</command> showed a query with a cost of 8488 was
reduced to a cost of 329. The original query was a join involving the reduced to a cost of 329. The original query was a join involving the
<structname>one_to_many</structname> table, which was replaced by: <structname>many_to_many</structname> table, which was replaced by:
<programlisting> <programlisting>
SELECT right, count(right) FROM SELECT id_right, count(id_right) FROM
( SELECT left, int_array_enum(right) AS right ( SELECT id_left, int_array_enum(rights) AS id_right
FROM summary JOIN (SELECT left FROM left_table WHERE left = <replaceable>item</replaceable>) AS lefts FROM summary
ON (summary.left = lefts.left) JOIN (SELECT id FROM left_table
WHERE id = <replaceable>item</replaceable>) AS lefts
ON (summary.id_left = lefts.id)
) AS list ) AS list
GROUP BY right GROUP BY id_right
ORDER BY count DESC; ORDER BY count DESC;
</programlisting> </programlisting>
</para> </para>