MySQL數據庫之rowid


MySQL數據庫之rowid

在oracle數據庫中,表默認以堆表的形式存儲。表中的每一行數據都有一個唯一的標識符稱為rowid,rowid標識了該行在oracle數據庫中的物理位置。在MySQL數據庫中也有rowid的概念。但是MySQL與oracle不同的是,MySQL的InnoDB引擎默認采用索引組織表。且rowid並不能直觀感受到。因此,大家可能會有以下疑惑:

1、如何感受到rowid的存在

2、rowid和主鍵有什么關系

3、如何來理解rowid的潛在瓶頸並調試驗證

4、在主鍵的使用中存在哪些隱患

索引組織表

索引組織表用一句話來概述就是,數據即索引,索引即數據。通俗的說就是表數據本身就是一顆B+樹,根據主鍵順序進行排列。在InnoDB引擎中,每張表都有主鍵,如果沒有顯示的定義主鍵。MySQL會按照如下方式定義主鍵:

1、首先判斷表中是否存在唯一非空索引,如果有,則該列為主鍵。當表中有多個非空唯一索引,InnoDB選擇建表時定義的第一個非空唯一索引為主鍵。

2、如果都不滿足上述條件,MySQL會自動創建一個6字節大小的指針。

_rowid介紹

在MySQL中存在一個隱藏列 _rowid 來標記唯一標識。但是需要注意的是 _rowid 並不是一個真實存在的列,本質是一個非空唯一列的別名。因此,在某些情況下 _rowid 是不存在的。它只存在於以下情況:

1、當表中存在一個數字類型的單列主鍵時, _rowid 其實指的就是這個主鍵列

2、當表中不存在主鍵但存在一個數字類型的非空唯一列時,  _rowid 其實指的就是這個對應的非空唯一列

詳情可以參考MySQL官方文檔:

示例:

mysql> create table test(a int primary key,b varchar(5));
Query OK, 0 rows affected (0.03 sec)

mysql> insert into test values(1,'a'),(2,'b'),(3,'c'),(4,'c'),(5,'d');
Query OK, 5 rows affected (0.00 sec)
Records: 5  Duplicates: 0  Warnings: 0

mysql> select _rowid from test;
+--------+
| _rowid |
+--------+
|      1 |
|      2 |
|      3 |
|      4 |
|      5 |
+--------+
5 rows in set (0.00 sec)

主鍵使用的隱患

主鍵性能問題不是一個單一的問題,需要MySQL方向持續改造的,將技術價值和業務價值結合起來。我看到很多業務中設置了自增列,但是大多數情況下,這種自增列卻沒有實際的業務含義,盡管是主鍵列保證了ID的唯一性,但是業務開發無法直接根據主鍵自增列來進行查詢,於是他們需要尋找新的業務屬性,添加一系列的唯一性索引,非唯一性索引等等,這樣一來我們堅持的規范和業務使用的方式就存在了偏差。

從另外一個維度來說,我們對於主鍵的理解是有偏差的,我們不能單一的認為主鍵就一定是從1開始的整數類型,我們需要結合業務場景來看待,比如我們的身份證其實就是一個不錯的例子,把證號分成了幾個區段,偏於檢索和維護;或者是外出就餐時得到的流水單號,它都有一定的業務屬性在里面,對於我們去理解業務的使用是一種不錯的借鑒。

rowid的瓶頸

我們知道rowid只有6個字節,因此最大值是2^48,所以一旦 row_id超過這個值還是會遞增,這種情況下是否存在隱患。我們來測試下:

1)、創建一張表test_inc,不包含任何索引。

create table test_inc(id int) engine=innodb;

2)、通過ps -ef|grep mysql得到對應的進程號,使用gdb來開始做下調試配置,切記!此處應該是自己的測試環境。

[root@all ~]# gdb -p 2295 -ex 'p dict_sys->row_id=1' -batch
[New LWP 3097]
[New LWP 2332]
[New LWP 2331]
[New LWP 2327]
[New LWP 2326]
[New LWP 2325]
[New LWP 2324]
[New LWP 2323]
[New LWP 2322]
[New LWP 2321]
[New LWP 2320]
[New LWP 2319]
[New LWP 2318]
[New LWP 2317]
[New LWP 2316]
[New LWP 2312]
[New LWP 2311]
[New LWP 2310]
[New LWP 2309]
[New LWP 2308]
[New LWP 2307]
[New LWP 2306]
[New LWP 2305]
[New LWP 2304]
[New LWP 2303]
[New LWP 2302]
[New LWP 2301]
[Thread debugging using libthread_db enabled]
0x0000003f290df1b3 in poll () from /lib64/libc.so.6
$1 = 1

3)、插入一些數據,使得rowid持續自增

insert into test_inc values(1),(2),(3);

4)、對rowid進行重置,調整為2^48

[root@all ~]# gdb -p 2295 -ex 'p dict_sys->row_id=281474976710656' -batch
。。。
。。。
[Thread debugging using libthread_db enabled]
0x0000003f290df1b3 in poll () from /lib64/libc.so.6
$1 = 281474976710656

5)、繼續寫入一些數據,比如我們寫入4,5,6三行數據,查詢結果

mysql> insert into test_inc values(4),(5),(6); 
Query OK, 3 rows affected (0.00 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> select *from test_inc;
+------+
| id   |
+------+
|    4 |
|    5 |
|    6 |
|    3 |
+------+
4 rows in set (0.00 sec)

查看數據結果,發現1,2兩行已經被覆蓋了。由此,我們可以看到rowid自增后,還是存在使用瓶頸,當然這個概率是很低的,需要自增列的值到281萬億,這是一個相當龐大的數值了,從功能上來說,應該拋出寫入重復值的錯誤更為合理。

而有了主鍵之后,上面這個瓶頸似乎就不存在了。


免責聲明!

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



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