欧美阿v视频在线大全_亚洲欧美中文日韩V在线观看_www性欧美日韩欧美91_亚洲欧美日韩久久精品

主頁 > 知識庫 > postgresql分頁數據重復問題的深入理解

postgresql分頁數據重復問題的深入理解

熱門標簽:辦公外呼電話系統 海豐有多少商家沒有地圖標注 漯河外呼電話系統 合肥公司外呼系統運營商 打電話智能電銷機器人授權 美容工作室地圖標注 地圖標注和圖片名稱的區別 重慶自動外呼系統定制 外呼調研系統

問題背景

許多開發和測試人員都可能遇到過列表的數據翻下一頁的時候顯示了上一頁的數據,也就是翻頁會有重復的數據。

如何處理?

這個問題出現的原因是因為選擇的排序字段有重復,常見的處理辦法就是排序的時候加上唯一字段,這樣在分頁的過程中數據就不會重復了。 關于這個問題文檔也有解釋并非是一個bug。而是排序時需要選擇唯一字段來做排序,不然返回的結果不確定

排序返回數據重復的根本原因是什么呢?

經常優化sql的同學可能會發現,執行計劃里面會有Sort Method這個關鍵字,而這個關鍵字就是排序選擇的方法。abase的排序分為三種

quicksort                       快速排序   
top-N heapsort  Memory          堆排序
external merge  Disk            歸并排序

推測

分頁重復的問題和執行計劃選擇排序算法的穩定性有關。

簡單介紹下這三種排序算法的場景:

在有索引的情況下:排序可以直接走索引。 在沒有索引的情況下:當表的數據量較小的時候選擇快速排序(排序所需必須內存小于work_mem), 當排序有limit,且耗費的內存不超過work_mem時選擇堆排序, 當work_mem不夠時選擇歸并排序。

驗證推測

1.創建表,初始化數據

abase=# create table t_sort(n_int int,c_id varchar(300));
CREATE TABLE
abase=# insert into t_sort(n_int,c_id) select 100,generate_series(1,9);
INSERT 0 9
abase=# insert into t_sort(n_int,c_id) select 200,generate_series(1,9);
INSERT 0 9
abase=# insert into t_sort(n_int,c_id) select 300,generate_series(1,9);
INSERT 0 9
abase=# insert into t_sort(n_int,c_id) select 400,generate_series(1,9);
INSERT 0 9
abase=# insert into t_sort(n_int,c_id) select 500,generate_series(1,9);
INSERT 0 9
abase=# insert into t_sort(n_int,c_id) select 600,generate_series(1,9);
INSERT 0 9

三種排序

--快速排序 quicksort
abase=# explain analyze select ctid,n_int,c_id from t_sort order by n_int asc;
            QUERY PLAN            
------------------------------------------------------------
 Sort (cost=3.09..3.23 rows=54 width=12) (actual time=0.058..0.061 rows=54 loops=1)
 Sort Key: n_int
 Sort Method: quicksort Memory: 27kB
 -> Seq Scan on t_sort (cost=0.00..1.54 rows=54 width=12) (actual time=0.021..0.032 rows=54 loops=1)
 Planning time: 0.161 ms
 Execution time: 0.104 ms
(6 rows)
--堆排序 top-N heapsort
abase=# explain analyze select ctid,n_int,c_id from t_sort order by n_int asc limit 10;
             QUERY PLAN             
 
------------------------------------------------------------
 Limit (cost=2.71..2.73 rows=10 width=12) (actual time=0.066..0.068 rows=10 loops=1)
 -> Sort (cost=2.71..2.84 rows=54 width=12) (actual time=0.065..0.066 rows=10 loops=1)
   Sort Key: n_int
   Sort Method: top-N heapsort Memory: 25kB
   -> Seq Scan on t_sort (cost=0.00..1.54 rows=54 width=12) (actual time=0.022..0.031 rows=54 loops=1
)
 Planning time: 0.215 ms
 Execution time: 0.124 ms
(7 rows)
--歸并排序 external sort Disk
--插入大量值為a的數據
abase=# insert into t_sort(n_int,c_id) select generate_series(1000,2000),'a';
INSERT 0 1001
abase=# set work_mem = '64kB';
SET
abase=# explain analyze select ctid,n_int,c_id from t_sort order by n_int asc;
             QUERY PLAN             
-------------------------------------------------------------
 Sort (cost=18.60..19.28 rows=270 width=12) (actual time=1.235..1.386 rows=1055 loops=1)
 Sort Key: n_int
 Sort Method: external sort Disk: 32kB
 -> Seq Scan on t_sort (cost=0.00..7.70 rows=270 width=12) (actual time=0.030..0.247 rows=1055 loops=1)
 Planning time: 0.198 ms
 Execution time: 1.663 ms
(6 rows)

快速排序

--快速排序
abase=# explain analyze select ctid,n_int,c_id from t_sort order by n_int asc;
            QUERY PLAN            
------------------------------------------------------------
 Sort (cost=3.09..3.23 rows=54 width=12) (actual time=0.058..0.061 rows=54 loops=1)
 Sort Key: n_int
 Sort Method: quicksort Memory: 27kB
 -> Seq Scan on t_sort (cost=0.00..1.54 rows=54 width=12) (actual time=0.021..0.032 rows=54 loops=1)
 Planning time: 0.161 ms
 Execution time: 0.104 ms
(6 rows) 
​
--獲取前20條數據
 abase=# select ctid,n_int,c_id from t_sort order by n_int asc limit 20;
  ctid | n_int | c_id 
 --------+-------+------
  (0,7) | 100 | 7
  (0,2) | 100 | 2
  (0,4) | 100 | 4
  (0,8) | 100 | 8
  (0,3) | 100 | 3
  (0,6) | 100 | 6
  (0,5) | 100 | 5
  (0,9) | 100 | 9
  (0,1) | 100 | 1
  (0,14) | 200 | 5
  (0,13) | 200 | 4
  (0,12) | 200 | 3
  (0,10) | 200 | 1
  (0,15) | 200 | 6
  (0,16) | 200 | 7
  (0,17) | 200 | 8
  (0,11) | 200 | 2
  (0,18) | 200 | 9
  (0,20) | 300 | 2
  (0,19) | 300 | 1
 (20 rows)  --分頁獲取前10條數據
 abase=# select ctid,n_int,c_id from t_sort order by n_int asc limit 10 offset 0;
  ctid | n_int | c_id 
 --------+-------+------
  (0,1) | 100 | 1
  (0,3) | 100 | 3
  (0,4) | 100 | 4
  (0,2) | 100 | 2
  (0,6) | 100 | 6
  (0,7) | 100 | 7
  (0,8) | 100 | 8
  (0,9) | 100 | 9
  (0,5) | 100 | 5
  (0,10) | 200 | 1
 (10 rows)
 --分頁從第10條開始獲取10條
 abase=# select ctid,n_int,c_id from t_sort order by n_int asc limit 10 offset 10;
  ctid | n_int | c_id 
 --------+-------+------
  (0,13) | 200 | 4
  (0,12) | 200 | 3
  (0,10) | 200 | 1
  (0,15) | 200 | 6
  (0,16) | 200 | 7
  (0,17) | 200 | 8
  (0,11) | 200 | 2
  (0,18) | 200 | 9
  (0,20) | 300 | 2
  (0,19) | 300 | 1
 (10 rows)

limit 10 offset 0,limit 10 offset 10,連續取兩頁數據

此處可以看到limit 10 offset 10結果中,第三條數據重復了第一頁的最后一條: (0,10) | 200 | 1

并且n_int = 200 and c_id = 5這條數據被“遺漏”了。

堆排序

abase=# select count(*) from t_sort;
 count 
-------
 1055
(1 row)
--設置work_mem 4MB
abase=# show work_mem ;
 work_mem 
----------
 4MB
(1 row)
​
--top-N heapsort
abase=# explain analyze select * from ( select ctid,n_int,c_id from test order by n_int asc limit 1001 offset 0) td limit 10;
              QUERY PLAN           
    
-------------------------------------------------------------------------------------------------------------
 Limit (cost=2061.33..2061.45 rows=10 width=13) (actual time=15.247..15.251 rows=10 loops=1)
 -> Limit (cost=2061.33..2063.83 rows=1001 width=13) (actual time=15.245..15.247 rows=10 loops=1)
   -> Sort (cost=2061.33..2135.72 rows=29757 width=13) (actual time=15.244..15.245 rows=10 loops=1)
    Sort Key: test.n_int
    Sort Method: top-N heapsort Memory: 95kB
    -> Seq Scan on test (cost=0.00..429.57 rows=29757 width=13) (actual time=0.042..7.627 rows=2
9757 loops=1)
 Planning time: 0.376 ms
 Execution time: 15.415 ms
(8 rows)
​
--獲取limit 1001 offset 0,然后取10前10條數據
abase=# select * from ( select ctid,n_int,c_id from test order by n_int asc limit 1001 offset 0) td limit 10;
 ctid | n_int | c_id 
----------+-------+------
 (0,6) | 100 | 6
 (0,2) | 100 | 2
 (0,5) | 100 | 5
 (87,195) | 100 | 888
 (0,3) | 100 | 3
 (0,1) | 100 | 1
 (0,8) | 100 | 8
 (0,55) | 100 | 888
 (44,12) | 100 | 888
 (0,9) | 100 | 9
(10 rows)
​---獲取limit 1001 offset 1,然后取10前10條數據
abase=# select * from ( select ctid,n_int,c_id from test order by n_int asc limit 1001 offset 1) td limit 10;
 ctid | n_int | c_id 
----------+-------+------
 (44,12) | 100 | 888
 (0,8) | 100 | 8
 (0,1) | 100 | 1
 (0,5) | 100 | 5
 (0,9) | 100 | 9
 (87,195) | 100 | 888
 (0,7) | 100 | 7
 (0,6) | 100 | 6
 (0,3) | 100 | 3
 (0,4) | 100 | 4
(10 rows)

---獲取limit 1001 offset 2,然后取10前10條數據
abase=# select * from ( select ctid,n_int,c_id from test order by n_int asc limit 1001 offset 2) td limit 10;
 ctid | n_int | c_id 
----------+-------+------
 (0,5) | 100 | 5
 (0,55) | 100 | 888
 (0,1) | 100 | 1
 (0,9) | 100 | 9
 (0,2) | 100 | 2
 (0,3) | 100 | 3
 (44,12) | 100 | 888
 (0,7) | 100 | 7
 (87,195) | 100 | 888
 (0,4) | 100 | 4
(10 rows)

堆排序使用內存: Sort Method: top-N heapsort  Memory: 95kB

當offset從0變成1后,以及變成2后,會發現查詢出的10條數據不是有順序的。

歸并排序

--將work_mem設置為64kb讓其走歸并排序。
abase=# set work_mem ='64kB';
SET
abase=# show work_mem;
 work_mem 
----------
 64kB
(1 row)
​
-- external merge Disk
abase=# explain analyze select * from ( select ctid,n_int,c_id from test order by n_int asc limit 1001 offset 0) td limit 10;
              QUERY PLAN               
---------------------------------------------------------------------------------------------------------------------------
 Limit (cost=2061.33..2061.45 rows=10 width=13) (actual time=27.912..27.916 rows=10 loops=1)
 -> Limit (cost=2061.33..2063.83 rows=1001 width=13) (actual time=27.910..27.913 rows=10 loops=1)
   -> Sort (cost=2061.33..2135.72 rows=29757 width=13) (actual time=27.909..27.911 rows=10 loops=1)
    Sort Key: test.n_int
    Sort Method: external merge Disk: 784kB
    -> Seq Scan on test (cost=0.00..429.57 rows=29757 width=13) (actual time=0.024..6.730 rows=29757 loops=1)
 Planning time: 0.218 ms
 Execution time: 28.358 ms
(8 rows)

​--同堆排序一樣,獲取limit 1001 offset 0,然后取10前10條數據
abase=# select * from ( select ctid,n_int,c_id from test order by n_int asc limit 1001 offset 0) td limit 10;
 ctid | n_int | c_id 
--------+-------+------
 (0,1) | 100 | 1
 (0,2) | 100 | 2
 (0,4) | 100 | 4
 (0,8) | 100 | 8
 (0,9) | 100 | 9
 (0,5) | 100 | 5
 (0,3) | 100 | 3
 (0,6) | 100 | 6
 (0,55) | 100 | 888
 (0,7) | 100 | 7
(10 rows)

--同堆排序一樣,獲取limit 1001 offset 1,然后取10前10條數據
abase=# select * from ( select ctid,n_int,c_id from test order by n_int asc limit 1001 offset 1) td limit 10;
 ctid | n_int | c_id 
----------+-------+------
 (0,2) | 100 | 2
 (0,4) | 100 | 4
 (0,8) | 100 | 8
 (0,9) | 100 | 9
 (0,5) | 100 | 5
 (0,3) | 100 | 3
 (0,6) | 100 | 6
 (0,55) | 100 | 888
 (0,7) | 100 | 7
 (87,195) | 100 | 888
(10 rows)

--同堆排序一樣,獲取limit 1001 offset 2,然后取10前10條數據
abase=# select * from ( select ctid,n_int,c_id from test order by n_int asc limit 1001 offset 2) td limit 10;
 ctid | n_int | c_id 
----------+-------+------
 (0,4) | 100 | 4
 (0,8) | 100 | 8
 (0,9) | 100 | 9
 (0,5) | 100 | 5
 (0,3) | 100 | 3
 (0,6) | 100 | 6
 (0,55) | 100 | 888
 (0,7) | 100 | 7
 (87,195) | 100 | 888
 (44,12) | 100 | 888
(10 rows)

減小work_mem使用歸并排序的時候,offset從0變成1后以及變成2后,任然有序。

還有一種情況,那就是在查詢前面幾頁的時候會有重復,但是越往后面翻就不會重復了,現在也可以解釋清楚。

如果每頁10條數據,當offse較小的時候使用的內存較少。當offse不斷增大,所耗費的內存也就越多。

--設置work_mem =64kb
abase=# show work_mem;
 work_mem 
----------
 64kB
(1 row)
--查詢limit 10 offset 10
abase=# explain analyze select * from ( select ctid,n_int,c_id from test order by n_int asc limit 10 offset 10) td limit 10;
              QUERY PLAN               
---------------------------------------------------------------------------------------------------------------------------
 Limit (cost=1221.42..1221.54 rows=10 width=13) (actual time=12.881..12.884 rows=10 loops=1)
 -> Limit (cost=1221.42..1221.44 rows=10 width=13) (actual time=12.879..12.881 rows=10 loops=1)
   -> Sort (cost=1221.39..1295.79 rows=29757 width=13) (actual time=12.877..12.879 rows=20 loops=1)
    Sort Key: test.n_int
    Sort Method: top-N heapsort Memory: 25kB
    -> Seq Scan on test (cost=0.00..429.57 rows=29757 width=13) (actual time=0.058..6.363 rows=29757 loops=1)
 Planning time: 0.230 ms
 Execution time: 12.976 ms
(8 rows)
​
--查詢limit 10 offset 1000
abase=# explain analyze select * from ( select ctid,n_int,c_id from test order by n_int asc limit 10 offset 1000) td limit 10;
              QUERY PLAN               
---------------------------------------------------------------------------------------------------------------------------
 Limit (cost=2065.75..2065.88 rows=10 width=13) (actual time=27.188..27.192 rows=10 loops=1)
 -> Limit (cost=2065.75..2065.78 rows=10 width=13) (actual time=27.186..27.188 rows=10 loops=1)
   -> Sort (cost=2063.25..2137.64 rows=29757 width=13) (actual time=26.940..27.138 rows=1010 loops=1)
    Sort Key: test.n_int
    Sort Method: external merge Disk: 784kB
    -> Seq Scan on test (cost=0.00..429.57 rows=29757 width=13) (actual time=0.026..6.374 rows=29757 loops=1)
 Planning time: 0.207 ms
 Execution time: 27.718 ms
(8 rows)

可以看到當offset從10增加到1000的時候,使用的內存增加,排序的方法從堆排序變成了歸并排序。而歸并排序為穩定排序,所以后面的分頁不會再有后一頁出現前一頁數據的情況。

參考資料:PostgreSQL - repeating rows from LIMIT OFFSET

參考資料: LIMIT and OFFSET

結語

1.關于分頁重復數據的問題主要是排序字段不唯一并且執行計劃走了快速排序和堆排序導致。

2.當排序有重復字段,但是如果查詢是歸并排序,便不會存在有重復數據的問題。

3.當用重復字段排序,前面的頁重復,隨著offset的增大導致work_mem不足以后使用歸并排序,就不存在重復的數據了。

4.排序和算法的穩定性有關,當執行計劃選擇不同的排序算法時,返回的結果不一樣。

5.處理重復數據的常見手段就是,排序的時候可以在排序字段d_larq(立案日期)后面加上c_bh(唯一字段)來排序。

order by d_larq,c_bh;

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,謝謝大家對腳本之家的支持。

您可能感興趣的文章:
  • PostgreSQL 重復數據處理的操作方法
  • postgresql數據合并,多條數據合并成1條的操作
  • postgresql數據添加兩個字段聯合唯一的操作
  • postgreSQL使用pgAdmin備份服務器數據的方法
  • Postgresql數據庫之創建和修改序列的操作
  • postgresql 刪除重復數據的幾種方法小結

標簽:烏海 株洲 錦州 衡陽 珠海 晉城 來賓 蚌埠

巨人網絡通訊聲明:本文標題《postgresql分頁數據重復問題的深入理解》,本文關鍵詞  postgresql,分頁,數據,重復,;如發現本文內容存在版權問題,煩請提供相關信息告之我們,我們將及時溝通與處理。本站內容系統采集于網絡,涉及言論、版權與本站無關。
  • 相關文章
  • 下面列出與本文章《postgresql分頁數據重復問題的深入理解》相關的同類信息!
  • 本頁收集關于postgresql分頁數據重復問題的深入理解的相關信息資訊供網民參考!
  • 推薦文章
    欧美阿v视频在线大全_亚洲欧美中文日韩V在线观看_www性欧美日韩欧美91_亚洲欧美日韩久久精品
  • <rt id="w000q"><acronym id="w000q"></acronym></rt>
  • <abbr id="w000q"></abbr>
    <rt id="w000q"></rt>
    久久久久久久久久网站| 欧美精选午夜久久久乱码6080| 国产成人精品免费在线| 东方欧美亚洲色图在线| 绯色av蜜臀vs少妇| 天堂久久久久久| 久久久视频6r| 色哟哟欧美精品| 欧美一区二区视频网站| 精品不卡在线视频| 国产精品国产自产拍高清av | 极品美女销魂一区二区三区| 国产麻豆成人精品| 潘金莲一级淫片aaaaaaa| 免费国产羞羞网站美图| 91麻豆精品国产91久久久使用方法| 欧美精品777| 亚洲国产美国国产综合一区二区| 亚洲一区二区三区美女| 狠狠色丁香久久婷婷综合_中| 国产精品白丝av| 欧美午夜精品一区二区| 一区二区三区在线播放视频| 欧美日韩一区二区在线观看视频 | 亚洲三级理论片| 蜜桃视频在线观看一区| av一区二区三区| 人人妻人人澡人人爽| 久久色在线观看| 亚洲不卡在线观看| 不卡视频在线看| 在线观看免费小视频| 日韩一级二级三级| 一区二区三区成人| 成人夜色视频网站在线观看| 亚洲一区二区三区日韩| 精品日韩成人av| 日韩高清国产一区在线| av欧美精品.com| 欧美日韩国产在线观看| 亚洲精品免费电影| 成人美女视频在线看| 在线观看视频一区二区 | 成人精品在线视频观看| www青青草原| 亚洲一级二级三级在线免费观看| 成人av电影在线播放| 欧美特级限制片免费在线观看| 在线综合视频播放| 久久精品国产精品亚洲红杏 | 精品国内片67194| 国产成人在线看| 波多野结衣不卡视频| 一卡二卡三卡日韩欧美| 右手影院亚洲欧美 | 日韩高清在线一区| a级大片免费看| 亚洲av毛片基地| 亚洲免费观看高清完整版在线观看熊| 天天色图综合网| 亚洲国产精品第一页| 日韩视频免费观看高清完整版在线观看 | 高清不卡一区二区在线| 羞羞在线观看视频| 26uuu欧美| 99久久99久久精品免费观看| 国产波霸爆乳一区二区| 午夜久久久久久久久久一区二区| 91免费观看视频在线| 欧美刺激脚交jootjob| 日韩中文字幕区一区有砖一区| 国产ts在线观看| 精品成人免费观看| 99精品偷自拍| 久久这里只有精品视频网| 91丨九色丨尤物| 久久女同性恋中文字幕| 91老师片黄在线观看| 久久久久久久精| 国产一区二区三区在线观看精品| 91激情视频在线观看| 亚洲精品午夜久久久| 91麻豆精品国产91久久综合| 一区2区3区在线看| 国产老头老太做爰视频| 亚洲免费观看高清完整版在线| 91欧美一区二区| 国产午夜精品一区二区三区视频| 天堂在线亚洲视频| 天堂网avav| 久久精品99国产精品日本| 欧美亚洲高清一区| 韩国理伦片一区二区三区在线播放 | 在线视频欧美区| 午夜欧美一区二区三区在线播放| 青青草视频播放| 亚洲精品成人a在线观看| 天堂av网手机版| 亚洲欧美另类综合偷拍| 国产午夜精品福利视频| 婷婷亚洲久悠悠色悠在线播放| 亚洲第一黄色网址| 亚洲欧美激情插| 无码人妻精品中文字幕 | jizzjizzjizz国产| 视频一区国产视频| 欧美性猛交xxxxxxxx| 成人免费高清视频在线观看| 久久精品亚洲精品国产欧美 | 免费无码一区二区三区| 一区二区三区四区激情| 天天看片中文字幕| 成人午夜在线免费| 久久久久久免费网| 欧美黄色一级生活片| 免费观看在线综合色| 日本a级片视频| 国产精品1区2区3区在线观看| 欧美吻胸吃奶大尺度电影 | 亚洲风情在线资源站| 亚洲欧美小视频| 国产福利91精品一区二区三区| 欧美日韩黄色影视| 欧美体内she精高潮| 一区二区三国产精华液| 日本韩国视频一区二区| 成人免费毛片片v| 国产精品久久久久久妇女6080 | 欧美一区二区网站| 国内精品免费视频| 一区二区在线观看免费| 欧洲一区二区av| 性一交一黄一片| 亚洲综合成人在线| 欧美日韩精品免费观看视频| 欧美高清精品一区二区| 亚洲夂夂婷婷色拍ww47| 欧美视频在线播放| 性猛交╳xxx乱大交| 亚洲成人免费av| 欧美精品久久久久久久多人混战 | 精品久久久久久久久久久院品网| caoporm超碰国产精品| 亚洲少妇30p| 欧美性受极品xxxx喷水| 动漫av在线免费观看| 天天影视色香欲综合网老头| 日韩精品中文字幕一区| 新91视频在线观看| 五月天中文字幕一区二区| 6080亚洲精品一区二区| 9.1成人看片免费版| 国产在线精品不卡| 国产精品欧美一区喷水| jizz中文字幕| 成人手机电影网| 夜夜爽夜夜爽精品视频| 91精品国产综合久久久久久| 亚洲AV无码片久久精品| 国产乱码一区二区三区| 亚洲天堂久久久久久久| 在线视频国内自拍亚洲视频| 亚洲精品第二页| 亚洲国产精品久久久久婷婷884| 亚洲国产成人精品综合99| 国产精品二区视频| 欧美bbbbb| 国产精品美女久久久久久久久久久| 香蕉视频久久久| 成人h动漫精品一区二区| 亚洲成在线观看| 2023国产精品| 欧美特级一级片| 特级特黄刘亦菲aaa级| 蜜桃久久久久久| 亚洲欧洲日韩综合一区二区| 日韩一级片大全| 青青草视频网站| 天堂一区二区在线免费观看| 久久久一区二区三区捆绑**| 在线观看xxx| a级在线观看视频| 成人性生交大片| 日本欧美韩国一区三区| 国产精品色噜噜| 宅男噜噜噜66一区二区66| 天天操夜夜操av| 好吊色视频一区二区三区| 日韩电影免费在线| 中文字幕免费一区| 色综合天天综合网天天狠天天| 蜜桃视频在线观看一区| 亚洲欧美自拍偷拍色图| 日韩一二三四区| 日本黄色一区二区| 国产精品美女高潮无套| 91丨九色丨尤物| 国产成人在线视频网站| 天堂一区二区在线| 亚洲精品国产精品乱码不99|