ORACLE的ORDERBY非穩定的排序

提一個問題: oracle在order by 排序時,是穩定排序算法嗎? 發現用一個type進行排序後,作分頁查詢,第一頁的數據和第二頁的數據有重複 懷疑是order by 時,兩次排列的順序不一致 php

看到業務描述的問題能夠獲得的結論order by排序不穩定,還有第一個印象就是,type確定是不惟一的,而且沒有索引吧。 html

這裏先科普下排序的穩定性,舉個最簡單的例子,1,2,3,1,4,5 排序 排序的結果是1,1,2,3,4,5,這時候觀察這個1,若是第一個1仍是排序前的那個1,那麼算法是穩定的。也就是說相等數在排序後不發生交換。 mysql

還記得之前數據結構中的幾種排序算法: 算法

選擇排序複雜度爲n*n,不穩定排序, sql

快速排序複雜度爲n*n,不穩定排序, shell

希爾排序複雜度爲nlogn,不穩定排序, 數據結構

堆排序複雜度爲nlogn,不穩定排序, oracle

冒泡排序複雜度爲n*n,穩定排序, 測試

插入排序複雜度爲n*n,穩定排序, ui

歸併排序複雜度爲nlogn,穩定排序

基數排序的複雜度和位數是有關的,是穩定排序。

好了回到正題,本機測試,插入幾條測試數據,表結構就兩個字段,id和name,沒有索引

SELECT ROWNUM,ZZ_TEST.* FROM ZZ_TEST;
1	2	test
2	2	test
3	3	test
4	4	test
5	1	test
能夠看到,默認差的時候是是按照rownum排序的。

而後按照name排序,

SELECT ROWNUM,ZZ_TEST.* FROM ZZ_TEST ORDER BY ZZ_TEST."name"
1	2	test
2	2	test
5	1	test
4	4	test
3	3	test
能夠看到,排列的順序不是按照rownum來排序了。

這裏再插入一個知識,如何在oracle裏查看執行計劃,我敲了半天的explain 發現沒有用。。。

原來是這麼看的,並且消息要比mysql詳細多了。:

Explain plan for SELECT ROWNUM,ZZ_TEST.* FROM ZZ_TEST ORDER BY ZZ_TEST."name"

select * from table(dbms_xplan.display());
-------------------------------------------------------------------------------
| Id  | Operation           | Name    | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |         |     1 |     8 |    16   (7)| 00:00:01 |
|   1 |  SORT ORDER BY      |         |     1 |     8 |    16   (7)| 00:00:01 |
|   2 |   COUNT             |         |       |       |            |          |
|   3 |    TABLE ACCESS FULL| ZZ_TEST |     1 |     8 |    15   (0)| 00:00:01 |
-------------------------------------------------------------------------------
好了,那麼排序和索引有沒有關係呢?

咱們先在type上面加一個索引試試,這裏我清空了從新插入了5個數據

SELECT ROWNUM,ZZ_TEST.* FROM ZZ_TEST ORDER BY ZZ_TEST."name"
1	3	test
2	4	test
5	2	test
4	1	test
3	5	test
貌似不給力啊老溼。

好,刪掉type的索引,在id上加索引,清空表再插入5個數據

SELECT ROWNUM,ZZ_TEST.* FROM ZZ_TEST ORDER BY ZZ_TEST."name"
1	3	test
2	4	test
5	2	test
4	1	test
3	5	test

好吧。原來帶上索引都不給力啊。。。

可是不對啊。。。總感受不對勁啊。沒錯。。。我TMD一直再用的rownum而不是rowID啊。我必定是最近寫分頁寫多了,坑爹啊。

這裏簡單的分辨一下rownum和rowid的區別,rownum是返回結果集的一個僞數列,用來標記返回結果的順序,而rowid是一個物理值用來標記存儲位置的。這個值是惟一而固定的

rowid和rownum都是虛列,但含義徹底不一樣。rowid是物理地址,用於定位oracle中具體數據的物理存儲位置,而rownum則是sql的輸出結果排序。通俗的講:rowid是相對不變的,rownum會變化,尤爲是使用order by的時候。
那麼咱們再查下rowid試試,這時候表沒有索引
SELECT rowid as rono,ROWNUM,ZZ_TEST.* FROM ZZ_TEST ORDER BY ZZ_TEST."name"
AAA7JjAB9AAAD+RAAA	1	3	test
AAA7JjAB9AAAD+RAAB	2	4	test
AAA7JjAB9AAAD+RAAG	5	2	test
AAA7JjAB9AAAD+RAAD	4	1	test
AAA7JjAB9AAAD+RAAC	3	5	test

感受rowno和rowid一個樣子啊

清空表,再在name上創建一個索引,而後在插入5條數據

AAA7JjAB9AAAD+RAAA	1	3	test
AAA7JjAB9AAAD+RAAB	2	4	test
AAA7JjAB9AAAD+RAAG	5	2	test
AAA7JjAB9AAAD+RAAD	4	1	test
AAA7JjAB9AAAD+RAAC	3	5	test
因此,也不是rowid的問題,oralce的排序就是不穩定的。

這裏有個小技巧,由於rownum的輸出順序並非排序的結果 那麼如何能輸出排序順序的rownum呢?可使用嵌套查詢,這個和分頁寫法是一個道理的

select ROWNUM ,t.* from (SELECT  rowid rono,ZZ_TEST.* FROM ZZ_TEST ORDER BY ZZ_TEST."name") t

這裏再插入一個小知識,如何在oracle下看錶的


select   *   from   user_tables   能夠查詢出全部的用戶表
select   table_name   from   user_tables;
查看其它信息能夠參考這個博客:


http://jerryhui.blog.51cto.com/109787/241127

這裏有一個博客的實驗結果是很符合預期的,可是我是真的沒有作出這個結果:

http://blog.csdn.net/gushangzao/article/details/7251138

http://www.itpub.net/forum.php?mod=viewthread&tid=1339419

/**

20121102 oracle的表類型

*/

http://www.2cto.com/database/201110/109559.html

原來oracle也分這麼多表類型,感受和mysql的不一樣的引擎差很少的。看這個介紹好像oracle的數據存儲確實和表類型有關,可是我找了半天不資料仍是不知道怎麼查看和更改表類型。求些靠譜資料。。。

總結一下,oralce的排序是不穩定的排序,對於相同字段的排序輸出結果貌似和索引和rowid都沒有規律可循,和網上的某些結論不太一致,這也是我今天比較困惑的地方。另外熟悉幾種排序的穩定性,會查看oracle的執行計劃,oracle如何看錶的名及表結構,知道rownum和rowid的區別,知道經過嵌套查詢輸出有規律的rownum

相關文章
相關標籤/搜索