【问题标题】:PostgreSQL: Sorting on alphanumeric string and decimal fieldPostgreSQL:按字母数字字符串和十进制字段排序
【发布时间】:2017-06-06 14:14:08
【问题描述】:

希望你们一切都好,一切都好!

我有一个表 items 有 200 万+条记录,结构如下所示:

id (int) | price (decimal) | priority (int)
-------------------------------------------
10001    |  59000.25       |    1
10002    |  73000.91       |    2
10003    |  1000.23        |    1
10004    |  9567.18        |    1

我正在寻找的解决方案非常简单:如何按 ASC|DESC 顺序在 price+priority 上对这张表进行排序?

当前可行的解决方案:我正在使用ORDER BY priority ASC, price ASC。但据我所知,对多列进行排序很慢且没有经过优化(因此我面临实时缓慢)。

我尝试过的解决方案:我已在此表中添加了一个临时列:

id (int) | price (decimal) | priority (int) | new_priority (varchar)
--------------------------------------------------------------------
10001    |  59000.25       |    1           | a59000.25
10002    |  73000.91       |    2           | b73000.91
10003    |  1000.23        |    1           | a1000.23
10004    |  9567.18        |    1           | a9567.18

我已经替换了 1 => a, 2 => b, 3 => c 直到 10(我在数据库中的最大数量)

现在,每当我尝试使用 SQL 时,它们都不起作用

SELECT * FROM items
ORDER BY new_priority ASC

SELECT * FROM items
ORDER BY new_priority::bytea

SELECT * FROM items
ORDER BY SUBSTRING(new_priority FROM '^(.*?)( \\d+)?$'),
     COALESCE(SUBSTRING(new_priority FROM ' (\\d+)$')::INTEGER, 0)

请指教!

我参考的链接:

  1. Postgresql sorting mixed alphanumeric data
  2. Alphanumeric Sorting in PostgreSQL
  3. Alphanumeric sorting with PostgreSQL
  4. Alphanumeric case in-sensitive sorting in postgres

【问题讨论】:

  • 在两列上创建索引 ASC。我敢打赌它会改善很多。
  • 好吧,排序数据是一个相当缓慢的过程,但是为什么要从 2mio+ 记录开始排序呢?通常您会处理数据子集,并且只对合理数量的行进行排序。
  • limitoffset 将无济于事,因为为了使其正常工作,数据库仍会进行全面扫描。数据库需要知道总量,因此它可以知道从哪里开始/停止使用限制/偏移子句。关于索引,它类似于create index idx_blabla on yourTable (priority ASC, price ASC) 供参考阅读:postgresql.org/docs/8.3/static/indexes-ordering.html
  • "因此我正面临实时缓慢" - 如果您的查询速度较慢,那么 Edit 您的问题并添加使用 explain (analyze, verbose) 生成的执行计划。 Formatted textno screen shots

标签: sql postgresql sorting pg


【解决方案1】:

创建一个index 怎么样?索引是一种提高数据库性能的机制。创建索引可能会很慢并且可能会持续几个小时,但您会注意到进一步查询的差异。

【讨论】:

    【解决方案2】:

    也许你可以使用NEW_PRIORITY 作为DECIMAL 来做一个更好的解决方案。

    假设PRICE 中的值不大于(例如)999999 并且PRIORITY 不是太“大”,您可以使用PRIORITY*1000000+PRICE

    无论如何,我认为使用 cmets 中所说的索引可能是一个更好的解决方案。

    要创建“复合索引”,您可以使用以下 sintax:

    CREATE INDEX index_name ON table_name (priority ASC, price ASC);
    

    【讨论】:

    • 我已经对这种方法进行了头脑风暴,并发现了一些漏洞,因此我不得不放弃这种方法。我有各种情况(例如,priority 是 1,price 是 1000.0,priority 是 2,价格是 5000.0。其次,price 可以达到任何数字,但优先级不大。基本上,我在将其保存到数据库之前正在计算优先级(基于一些规则)。
    • 不,@etsa 考虑这个:price=50000.5 and priority=10price=75000.0 and priority=5price=100.25 and priority=1。我总是希望在搜索结果的末尾看到最后一个第一个和第一个。
    • 好的,在我快速把你的文字变红之前,我看到了你的例子,你把字母放在价格之前。我认为复合索引是一个更好的解决方案(正如我在我的帖子中所写,之前编辑过),但是 - 只是为了好奇 - 要组成一个新列并根据需要对其进行排序,您应该添加一些固定的 '0' 或空格( ' ') 在新的复合列中,然后是优先级(例如 0000050000.500j 和 0000075000.000e 和 0000000100.250a)
    【解决方案3】:

    数据多久更改一次?如果不经常使用,请使用CLUSTER。 见:https://www.postgresql.org/docs/9.5/static/sql-cluster.html 它基本上会按照索引的顺序对表进行排序。 将此集群与 etsa 的答案结合起来。

    问题是,CLUSTER 无法维持秩序。 因此,如果您插入了新行,它将被插入到最后一行。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多