Postgresql 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

我有一个postgres表,其中包含大量不同长度的数字。例如,表的第一列将如下所示:

  • 一,
  • 十二,
  • 十三,
  • 134
  • 135
  • 136
  • 1362
  • 1363
  • 我需要postgres返回与给定数字开头尽可能多的匹配的行。例如,数字“1358302”需要与第5行(“135”)匹配,“1362304”需要与第7行(“1362”)匹配

    我可以使用什么SQL来实现这一点


    (数字还没有在那里永久排序,因此如果为了简单性/性能需要在整数或字符串之间切换数据类型,我仍然可以这样做!)

    暴力总是有效的

    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);