4

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

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

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

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

4

4 回答 4

4

LIKE不带通配符等同于=. 假设您实际上是说name = 'text'.

索引是性能的关键。

测试设置

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

理想情况下,您创建两个索引(除了主键):

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

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

询问

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

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;

SQL小提琴。

LIMIT子句适用于整个查询。Postgres 足够聪明,一旦找到足够的行来满足. 因此,对于第一个查询中的匹配,输出如下所示(向右滚动!):UNION ALLLIMIT SELECTEXPLAIN 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。空位排序的一种。

于 2013-01-16T18:53:58.263 回答
3

已经很晚了,我不想写出一个完整的解决方案,但是如果我需要这个,我可能会创建一个返回客户类型、记录或表格的客户函数(取决于您的需求)。这样做的好处是,一旦你找到你的记录,你就可以停下来。

使参数的数量是动态的将使其更具挑战性。根据您的 PostgreSQL 版本(以及您可用的扩展),您可能能够传入hstore或 json 并动态构建查询。

也许不是最好的 SO 答案,但它不仅仅是一个评论,希望是一些值得深思的东西。

于 2013-01-16T05:09:18.677 回答
2

在找到所需的结果之前,我认为单独运行这些查询没有任何问题。虽然有多种方法可以将这些组合到一个查询中,但最终会变得更复杂和更慢,这不是您想要的。

您应该考虑在一个事务中运行所有查询,这可能是可重复读取隔离级别的最佳选择,这样您可以获得一致的结果并避免设置重复事务的开销。此外,如果您明智地使用准备好的语句,您将拥有与在一个组合语句中运行所有三个查询几乎相同的开销。

于 2013-01-16T16:23:48.577 回答
1
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

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

于 2013-01-15T14:27:33.263 回答