为什么 PostgreSQL WINDOW 函数会影响 select 中所有行的最终排序?

Ant*_*al' 1 postgresql window-functions

假设我们有以下查询。

\n
select\n    name,\n    pos,\n    rank() over (partition by constructor) r,\n    format('%s / %s',\n        row_number() over (partition by constructor),\n        count(*) over (partition by constructor)\n    ) "pos/global"\nfrom (values\n        ('d1-c1', 1, 'c1'),\n        ('d3-c1', 3, 'c1'),\n        ('d3-c2', 3, 'c2'),\n        ('d2-c1', 2, 'c1'),\n        ('d2-c2', 2, 'c2')\n    ) t(name, pos, constructor);\n
Run Code Online (Sandbox Code Playgroud)\n

输出如下:

\n
 name  \xe2\x94\x82 pos \xe2\x94\x82 r \xe2\x94\x82 pos/global\n\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\xaa\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\xaa\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\xaa\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\n d1-c1 \xe2\x94\x82   1 \xe2\x94\x82 1 \xe2\x94\x82 1 / 3\n d3-c1 \xe2\x94\x82   3 \xe2\x94\x82 1 \xe2\x94\x82 2 / 3\n d2-c1 \xe2\x94\x82   2 \xe2\x94\x82 1 \xe2\x94\x82 3 / 3\n d3-c2 \xe2\x94\x82   3 \xe2\x94\x82 1 \xe2\x94\x82 1 / 2\n d2-c2 \xe2\x94\x82   2 \xe2\x94\x82 1 \xe2\x94\x82 2 / 2\n(5 rows)\n
Run Code Online (Sandbox Code Playgroud)\n

(此处可选问题:为什么每帧中的所有行都排名为1?)

\n

但是当我更改框架规范中的顺序时,

\n
select\n    name,\n    pos,\n    rank() over (partition by constructor order by pos asc) r,\n    format('%s / %s',\n        row_number() over (partition by constructor),\n        count(*) over (partition by constructor)\n    ) "pos/global"\nfrom (values\n        ('d1-c1', 1, 'c1'),\n        ('d3-c1', 3, 'c1'),\n        ('d3-c2', 3, 'c2'),\n        ('d2-c1', 2, 'c1'),\n        ('d2-c2', 2, 'c2')\n    ) t(name, pos, constructor);\n
Run Code Online (Sandbox Code Playgroud)\n

,我明白了:

\n
 name  \xe2\x94\x82 pos \xe2\x94\x82 r \xe2\x94\x82 pos/global\n\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\xaa\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\xaa\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\xaa\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\n d1-c1 \xe2\x94\x82   1 \xe2\x94\x82 1 \xe2\x94\x82 1 / 3\n d2-c1 \xe2\x94\x82   2 \xe2\x94\x82 2 \xe2\x94\x82 2 / 3\n d3-c1 \xe2\x94\x82   3 \xe2\x94\x82 3 \xe2\x94\x82 3 / 3\n d2-c2 \xe2\x94\x82   2 \xe2\x94\x82 1 \xe2\x94\x82 1 / 2\n d3-c2 \xe2\x94\x82   3 \xe2\x94\x82 2 \xe2\x94\x82 2 / 2\n(5 rows)\n
Run Code Online (Sandbox Code Playgroud)\n

...这就是我想要的,但我不明白为什么框架的顺序会影响所有其他行的顺序。我的直觉表明输出应该是这样的(只有r列中的值发生变化):

\n
 name  \xe2\x94\x82 pos \xe2\x94\x82 r \xe2\x94\x82 pos/global\n\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\xaa\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\xaa\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\xaa\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\n d1-c1 \xe2\x94\x82   1 \xe2\x94\x82 1 \xe2\x94\x82 1 / 3\n d3-c1 \xe2\x94\x82   3 \xe2\x94\x82 3 \xe2\x94\x82 2 / 3\n d2-c1 \xe2\x94\x82   2 \xe2\x94\x82 2 \xe2\x94\x82 3 / 3\n d3-c2 \xe2\x94\x82   3 \xe2\x94\x82 3 \xe2\x94\x82 1 / 2\n d2-c2 \xe2\x94\x82   2 \xe2\x94\x82 2 \xe2\x94\x82 2 / 2\n(5 rows)\n
Run Code Online (Sandbox Code Playgroud)\n

jka*_*lik 7

rank()函数按指定的顺序对行进行排名,您没有指定任何顺序,也没有固有的顺序,因此行是“相等的”并且全部都 get 1。在第二个查询中,您提供了一个顺序,它开始按预期工作。

对于主要问题 - 如果您没有为查询结果指定任何排序依据(您在任何一个查询中都没有指定排序依据),那么结果行的顺序是未定义的,数据库可以按照它喜欢的任何顺序返回它们(同一查询的两次执行之间可能有所不同)。通常优化器会尝试做尽可能少的工作来满足查询。

  • 在第一种情况下,保留原来的顺序,values因为不需要更改任何内容
  • 在第二种情况下,必须以某种方式对行进行排序才能解析rank(),并且由于该查询中不需要其他顺序,因此优化器决定values直接对行进行排序并将其用于输出(因为它仍然满足“未定义”最终)排序) - 不知道“优化器决定”是某种实际的优化还是只是代码中其他交互的副作用,实际上并不重要:)