Postgresql Postgres-尽可能匹配搜索参数的开头
我有一个postgres表,其中包含大量不同长度的数字。例如,表的第一列将如下所示:Postgresql Postgres-尽可能匹配搜索参数的开头,postgresql,search,large-files,Postgresql,Search,Large Files,我有一个postgres表,其中包含大量不同长度的数字。例如,表的第一列将如下所示: 一, 十二, 十三, 134 135 136 1362 1363 我需要postgres返回与给定数字开头尽可能多的匹配的行。例如,数字“1358302”需要与第5行(“135”)匹配,“1362304”需要与第7行(“1362”)匹配 我可以使用什么SQL来实现这一点 (数字还没有在那里永久排序,因此如果为了简单性/性能需要在整数或字符串之间切换数据类型,我仍然可以这样做!)暴力总是有效的 select m
(数字还没有在那里永久排序,因此如果为了简单性/性能需要在整数或字符串之间切换数据类型,我仍然可以这样做!)暴力总是有效的
select max(n)
from your_table
where n in (1, 13, 136, 1362, 13623, 136230, 1362304);
您可以在应用程序代码或存储过程中生成IN子句
或者,正如filiprem所做的那样,在子选择中生成它。在加载一个包含一百万个整数的表并查看执行计划之后,这似乎是灵活性和性能的最佳平衡。在大桌子上点餐很贵,我认为在这种情况下没有必要;最长的比赛将是最大的数字。(假设为非负整数。)
文字值1362304出现在两个位置。将其替换为参数
通过对子查询执行内部联接,而不是在WHERE子句中使用子查询,您可能可以再次将运行时间减半
with prefixes as (
select 1362304/(10^i)::int8 prefix
from generate_series(0,floor(log(1362304))::int) i
)
select max(n)
from numerals
inner join prefixes
on prefixes.prefix = numerals.n
最后一个版本在一百万行上以0.22毫秒(不是打字错误)的速度运行 考虑下面的演示
SELECT n
FROM your_table
WHERE n IN (
select $1/(10^i)::int8 from generate_series(0,floor(log($1))::int) i
)
ORDER BY n DESC
LIMIT 1
测试临时表:
CREATE TEMP TABLE nr(id int, nr numeric);
INSERT INTO nr VALUES
(1,1),(2,12),(3,13),(4,134),(5,135),
(6,136),(7,1362),(8,1363);
查询:
SELECT nr
FROM nr
WHERE '1362235' ~~ (nr::text || '%')
ORDER BY length(nr::text) DESC
LIMIT 1;
按要求提供最长的匹配。使用字符串(而不是数字)操作可以简化任务。您可以更改表中的数据类型,也可以像我一样在查询中强制转换值
如果您需要它是快速的,请将类型更改为文本
,并索引nr
。这样的搜索可以利用普通的btree索引(默认),而且速度非常快
如果数据库区域设置不是“C”或“POSIX”,请使用@Gavin注释,或者LIKE
运算符(~
)甚至不能在列的开头使用它,因为排序顺序是特定于区域设置的
CREATE INDEX nr_nr_idx ON nr (nr text_pattern_ops);
如果需要将表列设置为数字类型,则还有另一个选项。使用一个类似的例子:
上面的查询可以使用这样的索引,因为表达式与索引表达式匹配。hmm,“1362304”需要与第7行(“1362”)匹配,对吗?这个问题通常称为最长前缀匹配。使用该术语搜索信息可能会有所帮助。如果您有很多数据,请参阅可能值得在nr(nr text_pattern_ops)上创建索引nr_nr_idx。我没有想到以这种方式生成IN子句。我已经厚颜无耻地在我的答案中加入了你的代码。(但要感谢您。)
订购人。。。限制1在性能方面与max
@filiprem相当(甚至更快):我发布的版本,使用max(n)和你的subselect,在一百万行上运行了44ms。您的版本,使用ORDER BY…LIMIT 1,使用了780毫秒。Erwin的版本为960毫秒。更正:Erwin的版本使用Gavin建议的索引运行了333毫秒。稍后我会再看一看。我以前没有使用过可选的操作符类。
CREATE INDEX nr_nr_idx ON nr (nr);
CREATE INDEX nr_nr_idx ON nr (nr text_pattern_ops);
CREATE INDEX nr_nr_idx ON nr ((nr::text) text_pattern_ops);