如何尝试多个 SELECT 直到获得结果?

nep*_*epa 5 sql postgresql union postgresql-performance

如果我想以递减精度搜索表中的单行,例如:

SELECT * FROM image WHERE name LIKE 'text' AND group_id = 10 LIMIT 1
Run Code Online (Sandbox Code Playgroud)

如果这没有给我结果,请尝试这个:

SELECT * FROM image WHERE name LIKE 'text' LIMIT 1
Run Code Online (Sandbox Code Playgroud)

当这没有给我结果时,尝试这个:

SELECT * FROM image WHERE group_id = 10 LIMIT 1
Run Code Online (Sandbox Code Playgroud)

是否可以只用一种表达方式来做到这一点?

当我没有两个而是例如三个或更多搜索参数时,也会出现问题。有通用的解决方案吗?当然,当搜索结果按相关性排序时,它会派上用场。

Erw*_*ter 5

测试设置

CREATE TABLE image (
  image_id serial PRIMARY KEY
, group_id int NOT NULL
, name     text NOT NULL
);
Run Code Online (Sandbox Code Playgroud)

索引是性能的关键因素。理想情况下,除了主键之外,您还创建这两个:

CREATE INDEX image_name_grp_idx ON image (name, group_id);
CREATE INDEX image_grp_idx ON image (group_id);
Run Code Online (Sandbox Code Playgroud)

第二个可能不是必需的,具体取决于数据分布和其他细节。看:

询问

更新:Parallel Append当用于大型集合时,这在 Postgres 11 或更高版本中变得不可靠!考虑这个问题和答案(包括我的答案中的可靠替代方案):


对于您的情况,这应该是最快的查询:

CREATE INDEX image_name_grp_idx ON image (name, group_id);
CREATE INDEX image_grp_idx ON image (group_id);
Run Code Online (Sandbox Code Playgroud)

小提琴
sqlfiddle

LIKE没有通配符相当于=

LIMIT子句适用于整个查询。Postgres 足够聪明UNION ALL一旦找到足够的行来满足LIMIT. 因此,对于第一个 SELECT查询中的匹配,输出EXPLAIN ANALYZE如下所示(向右滚动!):

限制(成本=0.00..0.86行=1宽度=40)(实际时间=0.045..0.046行=1循环=1)
  缓冲区:本地命中=4
  ->结果(成本=0.00..866.59行=1002宽度=40)(实际时间=0.042..0.042行=1循环=1)
        缓冲区:本地命中=4
        ->追加(成本=0.00..866.59行=1002宽度=40)(实际时间=0.039..0.039行=1循环=1)
              缓冲区:本地命中=4
              -> 在图像上使用 image_name_grp_idx 进行索引扫描(成本=0.00..3.76行=2宽度=40)(实际时间=0.035..0.035行=1循环=1)
                    索引条件:((name = 'name105'::text) AND (group_id = 10))
                    缓冲区:本地命中=4
              -> 在图像上使用 image_name_grp_idx 进行索引扫描(成本=0.00..406.36 行=500 宽度=40)(从未执行)
                    索引条件: (name = 'name105'::text)
              -> 在图像上使用 image_grp_idx 进行索引扫描(成本=0.00..406.36 行=500 宽度=40)(从未执行)
                    索引条件:(group_id = 10)
总运行时间:0.087 毫秒

大胆强调我的。

不要添加外部ORDER BY子句,这会使效果无效。然后 Postgres 在返回顶行之前必须考虑所有行。

最后的问题

有通用的解决方案吗?

通用解决方案。添加SELECT任意数量的语句。

当然,当搜索结果按相关性排序时,它会派上用场。

结果中只有一行LIMIT 1。一种空洞排序。