查询限制和偏移量,有可能在Postgres中使用相同的查询获得不同的结果

时间:2016-09-24 20:19:43

标签: sql postgresql

基于Postgres文档偏移量是:

  

OFFSET表示在开始返回行之前跳过那么多行。

考虑到这一点,我想知道sql查询的默认排序/无排序逻辑是否对它有影响,使用默认排序时是否有机会使用相同的查询得到不同的结果?

2 个答案:

答案 0 :(得分:1)

评论太长了。

OFFSETLIMIT被用作查询处理的最后一步,实际上是从查询返回结果集时。

如果查询没有ORDER BY,则查询结果采用 indeterminate 顺序。事实上,结果的排序可能会因查询的一次运行而异。

即使使用ORDER BY,您也会获得不确定的订单 - 当行具有相同的键值时。 SQL中的排序不稳定(稳定排序总是以相同的顺序返回行)。原因很简单:SQL表代表无序集,因此没有"自然"命令定义一个稳定的排序。

如果您关心一致排序的数据,那么您应该始终使用ORDER BY。而且,您应该确保键组合唯一地定义每一行。如果他们不这样做,请将主键作为ORDER BY的最后一个键。

答案 1 :(得分:0)

对于默认情况下获得不同的结果(意味着没有顺序),确定这将基于SQL如何优化查询从1运行到另一个运行,但我猜想通常DML操作(如插入或删除)将是区分结果的最大罪魁祸首。

CREATE TABLE ExampleTable (Id INTEGER, Letter CHAR(1));

INSERT INTO ExampleTable (Id,Letter) VALUES (1,'A'),(5,'C'),(3,'B');


SELECT *
FROM
    ExampleTable
ORDER BY 1    
LIMIT 1 OFFSET 1
;

SELECT 'Example 1' as Example, *
FROM
    ExampleTable
ORDER BY 1    
LIMIT 1 OFFSET 1;

INSERT INTO ExampleTable (Id, Letter) VALUES (2,'D');

SELECT *
FROM
    ExampleTable
ORDER BY 1    
LIMIT 1 OFFSET 1
;

SELECT 'Example 1' as Example, *
FROM
    ExampleTable
ORDER BY 1    
LIMIT 1 OFFSET 1;

第一个结果是3,b第二个结果是2,D稍后当使用其他列运行时,我得到了5,c & 5,C。当没有额外的专用值时,PostresSQL正在优化INTEGER上的查询。因此,这会导致默认(无顺序)与查询不同。 [http://rextester.com/YJKC24018]

现在考虑通过LETTER排序:

CREATE TABLE ExampleTable2 (Id INTEGER, Letter CHAR(1));

INSERT INTO ExampleTable2 (Id,Letter) VALUES (1,'A'),(3,'C'),(4,'D');

SELECT *
FROM
    ExampleTable2
ORDER BY Letter
LIMIT 1 OFFSET 1
;

INSERT INTO ExampleTable2 (Id,Letter) VALUES (2,'B');

SELECT *
FROM
    ExampleTable2
ORDER BY Letter
LIMIT 1 OFFSET 1
;   

第一个结果为3,C,但第二个结果为2,B。因此,即使您选择了偏移量,因为记录集已更改,您可以获得相同的行或新行[http://rextester.com/IBI93830]

CREATE TABLE ExampleTable3 (Id INTEGER, Letter CHAR(1));

INSERT INTO ExampleTable3 (Id,Letter) VALUES (1,'A'),(3,'C'),(4,'D');

SELECT *
FROM
    ExampleTable3
ORDER BY Letter
LIMIT 1 OFFSET 1
;

INSERT INTO ExampleTable3 (Id,Letter) VALUES (2,'B');

SELECT *
FROM
    ExampleTable3
ORDER BY Letter
LIMIT 1 OFFSET 2
;    

因此,这是一个示例,在您收到的最后一条记录(2,B)之前插入了新记录(3,C)。因此,即使您增加了OFFSET,您实际上也会再次获得相同的行(3,C)。 [http://rextester.com/KRVIF54374]

CREATE TABLE ExampleTable4 (Id SERIAL, Letter CHAR(1));

INSERT INTO ExampleTable4 (Letter) VALUES ('A'),('C'),('D');

SELECT *
FROM
    ExampleTable4
ORDER BY Id
LIMIT 1 OFFSET 1
;

INSERT INTO ExampleTable4 (Letter) VALUES ('B');

SELECT *
FROM
    ExampleTable4
ORDER BY Id
LIMIT 1 OFFSET 1
;    

DELETE FROM ExampleTable4 WHERE Letter = 'C';

SELECT *
FROM
    ExampleTable4
ORDER BY Id
LIMIT 1 OFFSET 1
;    

此示例显示ID上的顺序可以保持一致,除非在表上发生删除,现在结果已使用相同的查询进行了更改。 [http://rextester.com/LTN10302]