postgresql 尝试多个SELECT直到结果可用的方法?

evrscar2  于 2022-11-23  发布在  PostgreSQL
关注(0)|答案(4)|浏览(113)

如果我想在一个表中搜索一行,并且精度递减,例如:

SELECT * FROM image WHERE name LIKE 'text' AND group_id = 10 LIMIT 1

如果没有结果,请尝试以下方法:

SELECT * FROM image WHERE name LIKE 'text' LIMIT 1

如果没有结果,试试这个:

SELECT * FROM image WHERE group_id = 10 LIMIT 1

有没有可能只用一个表达式就能做到这一点?
当我有三个或更多的搜索参数而不是两个时,也会出现一个问题。有没有一个通用的解决方案?当然,当搜索结果按其相关性排序时,它会很方便。

bprjcwpo

bprjcwpo1#

我不认为在找到所需结果之前分别运行这些查询有什么问题。虽然有一些方法可以将这些查询合并到一个查询中,但这些方法最终会变得更复杂、更慢,这不是您所希望的。
您应该考虑在一个事务处理中运行所有查询,最好是在可重复读取隔离级别中运行,这样可以获得一致的结果,同时避免设置重复事务处理的开销。此外,如果明智地使用预准备语句,则所产生的开销几乎与在一个组合语句中运行所有三个查询的开销相同。

k5hmc34c

k5hmc34c2#

SELECT *, 
CASE WHEN name like 'text' AND group_id = 10 THEN 1
WHEN name like 'text' THEN 2
WHEN group_id = 10 THEN 3
ELSE 4
END ImageRank
FROM image
WHERE ImageRank <> 4
ORDER BY ImageRank ASC
LIMIT 1

这将是一种伪解决方案方法,但我不完全确定您的场景中的语法是否允许这样做

xqkwcwgp

xqkwcwgp3#

测试设置

CREATE TABLE image (
  image_id serial PRIMARY KEY
, group_id int NOT NULL
, name     text NOT NULL
);

Indexes是性能的关键要素。理想情况下,除了主键之外,还创建以下两个:

CREATE INDEX image_name_grp_idx ON image (name, group_id);
CREATE INDEX image_grp_idx ON image (group_id);

第二个 * 可能 * 不需要,具体取决于数据分布和其他详细信息。请参阅:

查询

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

这应该是对您的案例而言最快的查询:

SELECT * FROM image WHERE name = 'name105' AND group_id = 10
UNION ALL
SELECT * FROM image WHERE name = 'name105'
UNION ALL
SELECT * FROM image WHERE group_id = 10
LIMIT  1;

fiddle
古老的SQLFIDLE
不带通配符的LIKE等效于=
LIMIT子句适用于整个查询。Postgres非常聪明,不会在找到足够的行来满足LIMIT时立即执行UNION ALL后面的分支。因此,对于查询的 * 第一个 * SELECT中的匹配项,EXPLAIN ANALYZE的输出如下所示(向右滚动!):

Limit  (cost=0.00..0.86 rows=1 width=40) (actual time=0.045..0.046 rows=1 loops=1)
  Buffers: local hit=4
  ->  Result  (cost=0.00..866.59 rows=1002 width=40) (actual time=0.042..0.042 rows=1 loops=1)
        Buffers: local hit=4
        ->  Append  (cost=0.00..866.59 rows=1002 width=40) (actual time=0.039..0.039 rows=1 loops=1)
              Buffers: local hit=4
              ->  Index Scan using image_name_grp_idx on image  (cost=0.00..3.76 rows=2 width=40) (actual time=0.035..0.035 **rows=1 loops=1**)
                    Index Cond: ((name = 'name105'::text) AND (group_id = 10))
                    Buffers: local hit=4
              ->  Index Scan using image_name_grp_idx on image  (cost=0.00..406.36 rows=500 width=40) **(never executed)**
                    Index Cond: (name = 'name105'::text)
              ->  Index Scan using image_grp_idx on image  (cost=0.00..406.36 rows=500 width=40) **(never executed)**
                    Index Cond: (group_id = 10)
Total runtime: 0.087 ms

大胆强调我的。

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

最后的问题

有没有一个通用的解决方案?
一般解决方案。根据需要添加任意多个SELECT语句。
当然,当搜索结果按其相关性排序时,它会派上用场。
结果中只有一行具有LIMIT 1。这是一种空排序。

qv7cva1a

qv7cva1a4#

现在已经很晚了,我不想写出一个完整的解决方案,但是如果我需要的话,我可能会创建一个客户function,它返回一个客户类型、记录或表(取决于您的需要)。
根据PostgreSQL的版本(以及可用的扩展),您可以传入hstore或json,然后dynamically来构建查询。
也许不是最好的答案,但它不仅仅是一个评论,希望一些思考的食物。

相关问题