用于搜索可以位于三个不同表中的唯一ID的SQL查询

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)

Erw*_*ter 5

PL/pgSQL函数

要解决手头的问题,像下面这样的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.


CTE(实验!)

如果由于某种原因无法创建函数,则此纯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上.
单独升级会大大加快操作速度.


查询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)