查询表中的连接字段

时间:2014-10-17 15:09:55

标签: sql postgresql indexing pattern-matching

我在PostgreSQL中有2个表a& b

CREATE TABLE a
(
  id serial PRIMARY,
  name character varying(50) NOT NULL,
);

CREATE TABLE b
(
  id serial PRIMARY,
  name character varying(50) NOT NULL,
  a_id integer,
  CONSTRAINT a_id_fk FOREIGN KEY (a_id) REFERENCES a (id) 
);

此外,我在b上有这两个部分索引,以确保b.namea为空时是唯一的,否则(a.name, b.name)对是唯一的。

  CREATE UNIQUE INDEX idx1 ON b (name, a_id) WHERE a_id IS NOT NULL;
  CREATE UNIQUE INDEX idx2 ON b (name) WHERE a_id IS NULL;

如果我想查询格式为a.name + ' ' + b.name的字符串,这是最有效的方法吗?反正我是否可以创建一个索引来确保(a.name, b.name)的唯一性,并使用它来有效地查询它?

SELECT * FROM b
INNER JOIN a on b.a_id = a.id
WHERE CONCAT(a.name, ' ' , b.name) = 'some string';

我需要精确查找,不需要LIKE / CONTAINS

1 个答案:

答案 0 :(得分:1)

首先,您需要额外的UNIQUE约束来满足您的要求:

  

否则(a.name, b.name)对是唯一的。

CREATE TABLE a (
 , id   serial PRIMARY KEY
 , name text UNIQUE NOT NULL
);

MATERIALIZED VIEW

这可以在任何情况下快速运行:带有连接字符串的MATERIALIZED VIEW。由于ab已关联,因此我们只会获得b中的行数,而不是笛卡尔积。

CREATE MATERIALIZED VIEW ab AS
SELECT b.a_id, b.id, concat_ws(' ', a.name, b.name) AS abname
FROM   b
LEFT   JOIN a ON a.id = b.a_id;

由于你只使用了相等,现在就有了一个简单的b树索引:

CREATE INDEX ab_abname_idx ON ab (abname);

查询:

SELECT *
FROM   ab
-- optionally (left) join to a and b ...
WHERE  abname = 'some string';
  • LEFT JOIN对于ba_id IS NULL的行包含至关重要。

  • concat_ws()仅插入a.name不是NULL的空格。

  • 根据您的访问模式刷新实体化视图。如果你有并发写访问权,这可能是棘手的部分。

没有MATERIALIZED VIEW

'some string' LIKE (a.name || '%')

不是sargable。索引支持是不可能的。你必须扭转表达式:

a.name = left('some string', length(a.name))

仍然不是可以接受的。你必须一步一步地做到这一点:

a.name = left('some string', 1) OR
a.name = left('some string', 2) OR
a.name = left('some string', 3) OR
...

这可以通过索引来支持。关于dba.SE的相关答案:

我会使用递归CTE来查找所有匹配...