sql分頁遍歷出現重復數據原因與解決方案


1. 問題描述

有同時反饋,直接通過如下的sql進行分頁查詢,分頁會出現重復數據,於是乎我專門查了相關了資料,整理了一下。

-- 根據sort字段對dbname進行排序,每五百條數據一頁
SELECT * FROM  (  
	SELECT A.*, ROWNUM RN  FROM ( 
		select * from dbname
		where createtime between '20211212' and '20211213') A  
	WHERE ROWNUM <=7000 )  
WHERE RN >6500

2. 問題分析

可能的問題原因

2.1 Oracle 的 order by 是穩定排序么?

根據oracle官方文檔:ORDER BY clauses,里邊有針對排序是否穩定做了說明。

EQL保證語句的結果在查詢中是穩定的。這意味着:

  • 如果沒有執行更新,則即使沒有指定ORDER BY子句,或者ORDER BY句中指定的順序有聯系,同一語句也會在重復查詢時以相同的順序返回結果。
  • 如果執行了更新,那么只有明確影響訂單的更改才會影響訂單;訂單不會受到其他影響。訂單可能會受到更改的影響,例如刪除或插入有助於返回頁面上或之前結果的記錄,或修改用於分組或訂購的值。

例如,在沒有ORDER BY子句的語句中,使用PAGE(0, 10)然后是PAGE(10, 10)然后是PAGE(20, 10)查詢,在沒有更新的情況下,從同一任意但穩定的結果返回連續的10條記錄。

對於帶有更新的示例,在帶有ORDER BY Num PAGE(3, 4)的語句中,初始查詢返回記錄{5、6、7、8}。然后,更新插入帶有4的記錄(在指定頁之前),刪除帶有6的記錄(在指定頁上),並插入帶有9的記錄(在指定頁之后)。更新后,同一查詢的結果將為{4、5、7、8}。這是因為:

  • 插入4將所有后續結果向下移動一個。抵消3條記錄包括新記錄。
  • 刪除6個班次會將所有后續結果增加一個。
  • 插入9不影響此結果之前或包含的任何記錄。

從官方文檔的描述來看,只要加上order by,那么在沒有影響到該查詢條件的更新或者寫入操作,則排序是不受影響的,是穩定的。官方文檔的描述比較符合我的預期,因為我覺得要是我去實現,我就會使用穩定排序的算法去實現,而不是非穩定算法。

我看網絡上充斥着這片文章:Oracle——分頁查詢出現重復數據問題的分析與解決,該文章提到一個觀點需要唯一索引才能夠保證分頁排序不會重復。我覺得看法太淺了,相當於提出了解決方案,但是不知道為什么能夠解決沒有了解,另外就是文章感覺個人主觀猜想太強了,理論沒有依據來源的感覺,可信度就感覺比較低。根據官方文檔的說明,實際只要加上排序即可保證分頁遍歷是不會出現重復數據的。

3. 解決方法

3.1 通過排序分頁

我想這是最高效的寫法,只要在createtime 字段加上索引,則查詢和排序都會利用到該索引。

-- 根據sort字段對dbname進行排序,每五百條數據一頁
SELECT * FROM  (  
	SELECT A.*, ROWNUM RN  FROM ( 
		select * from dbname
		where createtime between '20211212' and '20211213'
		order by createtime) A  
	WHERE ROWNUM <=7000 )  
WHERE RN >6500


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM