Mar*_*ato 5 sql postgresql postgresql-8.1
我有三个控制产品,颜色和尺寸的桌子.产品可以有或没有颜色和大小.颜色可以或不具有尺寸.
product color size
------- ------- -------
id id id
unique_id id_product (FK from product) id_product (FK from version)
stock unique_id id_version (FK from version)
title stock unique_id
stock
Run Code Online (Sandbox Code Playgroud)
unique_id所有表中都存在的列是一个串行类型(自动增量),它的计数器与三个表共享,基本上它作为它们之间的全局唯一ID.
它工作正常,但我想在我必须选择一些基于的字段时提高查询性能unique_id.
因为我不知道unique_id我在找什么,我正在使用UNION,如下所示:
select title, stock
from product
where unique_id = 10
UNION
select p.title, c.stock
from color c
join product p on c.id_product = p.id
where c.unique_id = 10
UNION
select p.title, s.stock
from size s
join product p on s.id_product = p.id
where s.unique_id = 10;
Run Code Online (Sandbox Code Playgroud)
有一个更好的方法吗?谢谢你的任何建议!
编辑1
基于@ErwinBrandstetter和@ErikE的答案,我决定使用以下查询.主要原因是:
1)正如unique_id所有表格中的索引一样,我将获得良好的表现
2)使用unique_idi将找到产品代码,因此我可以使用另一个简单的连接获得我需要的所有列
SELECT
p.title,
ps.stock
FROM (
select id as id_product, stock
from product
where unique_id = 10
UNION
select id_product, stock
from color
where unique_id = 10
UNION
select id_product, stock
from size
where unique_id = 10
) AS ps
JOIN product p ON ps.id_product = p.id;
Run Code Online (Sandbox Code Playgroud)
要解决手头的问题,像下面这样的plpgsql函数应该更快:
CREATE OR REPLACE FUNCTION func(int)
RETURNS TABLE (title text, stock int) LANGUAGE plpgsql AS
$BODY$
BEGIN
RETURN QUERY
SELECT p.title, p.stock
FROM product p
WHERE p.unique_id = $1; -- Put the most likely table first.
IF NOT FOUND THEN
RETURN QUERY
SELECT p.title, c.stock
FROM color c
JOIN product p ON c.id_product = p.id
WHERE c.unique_id = $1;
END;
IF NOT FOUND THEN
RETURN QUERY
SELECT p.title, s.stock
FROM size s
JOIN product p ON s.id_product = p.id
WHERE s.unique_id = $1;
END IF;
END;
$BODY$;
Run Code Online (Sandbox Code Playgroud)
使用表限定列名更新了函数,以避免命名与OUT参数冲突.
RETURNS TABLE需要PostgreSQL 8.4,RETURN QUERY需要8.2版.您可以将两者替换为旧版本.
不言而喻,您需要索引unique_id每个涉及的表的列.id应该自动编入索引,作为主键.
理想情况下,您可以单独从ID中分辨出哪个表.您可以继续使用一个常见的序列,但添加100000000第一个表,200000000第二个和300000000第三个 - 或任何适合您的需要.这样,数字中最不重要的部分很容易区分.
一个普通的整数跨越从-2147483648到+2147483647的数字,bigint如果这对你来说还不够.integer如果可能的话,我会坚持使用ID.它们比bigint或更小更快text.
如果由于某种原因无法创建函数,则此纯SQL解决方案可能会执行类似的操作:
WITH x(uid) AS (SELECT 10) -- provide unique_id here
, a AS (
SELECT title, stock
FROM x, product
WHERE unique_id = x.uid
)
, b AS (
SELECT p.title, c.stock
FROM x, color c
JOIN product p ON c.id_product = p.id
WHERE NOT EXISTS (SELECT 1 FROM a)
AND c.unique_id = x.uid
)
, c AS (
SELECT p.title, s.stock
FROM x, size s
JOIN product p ON s.id_product = p.id
WHERE NOT EXISTS (SELECT 1 FROM b)
AND s.unique_id = x.uid
)
SELECT * FROM a
UNION ALL
SELECT * FROM b
UNION ALL
SELECT * FROM c;
Run Code Online (Sandbox Code Playgroud)
我不确定它是否会像我希望的那样避免额外扫描.必须进行测试.此查询至少需要PostgreSQL 8.4.
正如我刚刚了解到的,OP运行在PostgreSQL 8.1上.
单独升级会大大加快操作速度.
由于您的选项有限,并且无法使用plpgsql函数,因此该函数应该比您拥有的函数更好.测试EXPLAIN ANALYZE - 在v8.1中可用.
SELECT title, stock
FROM product
WHERE unique_id = 10
UNION ALL
SELECT p.title, ps.stock
FROM product p
JOIN (
SELECT id_product, stock
FROM color
WHERE unique_id = 10
UNION ALL
SELECT id_product, stock
FROM size
WHERE unique_id = 10
) ps ON ps.id_product = p.id;
Run Code Online (Sandbox Code Playgroud)