MySQL 字符串主鍵和整型主鍵分析


背景:

      工作中需要把UUID的主鍵改成整型自增的主鍵,雖然知道INNODB的一些特性,改成自增主鍵之后會提升很多,但是沒有測試。在測試過程中<左興宇>給了很多幫助,非常感謝。

測試一:

View Code
root@localhost : test 11:32:17>show create table test\G;
*************************** 1. row ***************************
       Table: test
Create Table: CREATE TABLE `test` (
  `uid` char(36) NOT NULL DEFAULT '',
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `status` tinyint(4) DEFAULT NULL,
  PRIMARY KEY (`uid`),  /*uid*/
  KEY `idx_id` (`id`)  /*id,uid*/
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

root@localhost : test 11:32:24>show create table test_bak\G;
*************************** 1. row ***************************
       Table: test_bak
Create Table: CREATE TABLE `test_bak` (
  `uid` char(36) NOT NULL DEFAULT '',
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `status` tinyint(4) DEFAULT NULL,
  PRIMARY KEY (`id`), /*id*/
  KEY `idx_id` (`uid`) /*uid,id*/
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

root@localhost : test 11:32:29>insert into test(uid,name,status) select uuid(),agencyName,status from infoSort;
Query OK, 639759 rows affected (25.02 sec)
Records: 639759  Duplicates: 0  Warnings: 0

root@localhost : test 11:34:21>insert into test_bak(uid,name,status) select uuid(),agencyName,status from infoSort;
Query OK, 639759 rows affected (20.28 sec)
Records: 639759  Duplicates: 0  Warnings: 0

表test是UUID為主鍵的表,test_bak是自增ID為主鍵的表。分析:從表大小,以及插入和查詢的性能等方面分析。表大小:

View Code
-rw-rw---- 1 mysql mysql 8.5K 2012-09-21 11:32 test_bak.frm
-rw-rw---- 1 mysql mysql 104M 2012-09-21 11:35 test_bak.ibd
-rw-rw---- 1 mysql mysql 8.5K 2012-09-21 11:30 test.frm
-rw-rw---- 1 mysql mysql 104M 2012-09-21 11:34 test.ibd

上面查看表的物理文件大小,2張表大小剛好一樣,通過innodb_table_monitor來查看他們的具體信息:

TABLE: name test/test, id 0 718, flags 1, columns 7, indexes 2, appr.rows 635787
   COLUMNS: uid: DATA_MYSQL DATA_NOT_NULL len 108; id: DATA_INT DATA_BINARY_TYPE DATA_NOT_NULL len 4; name: DATA_VARMYSQL len 765; status: DATA_INT DATA_BINARY_TYPE len 1; DB_ROW_ID: DATA_SYS prtype 256 len 6; DB_TRX_ID: DATA_SYS prtype 257 len 6; DB_ROLL_PTR: DATA_SYS prtype 258 len 7;
   INDEX: name PRIMARY, id 0 1387, fields 1/6, uniq 1, type 3
   root page 3, appr.key vals 635787, leaf pages 4056, size pages 4078
   FIELDS:  uid DB_TRX_ID DB_ROLL_PTR id name status
   INDEX: name idx_id, id 0 1388, fields 1/2, uniq 2, type 0
   root page 4, appr.key vals 638241, leaf pages 1834, size pages 1896
   FIELDS:  id uid /*表中定義的二級索引明明只有id,為什么最右邊又會出現uid列呢*/
--------------------------------------
   TABLE: name test/test_bak, id 0 719, flags 1, columns 7, indexes 2, appr.rows 619056
   COLUMNS: uid: DATA_MYSQL DATA_NOT_NULL len 108; id: DATA_INT DATA_BINARY_TYPE DATA_NOT_NULL len 4; name: DATA_VARMYSQL len 765; status: DATA_INT DATA_BINARY_TYPE len 1; DB_ROW_ID: DATA_SYS prtype 256 len 6; DB_TRX_ID: DATA_SYS prtype 257 len 6; DB_ROLL_PTR: DATA_SYS prtype 258 len 7;
   INDEX: name PRIMARY, id 0 1389, fields 1/6, uniq 1, type 3
   root page 3, appr.key vals 619056, leaf pages 4056, size pages 4070
   FIELDS:  id DB_TRX_ID DB_ROLL_PTR uid name status
   INDEX: name idx_id, id 0 1390, fields 1/2, uniq 2, type 0
   root page 4, appr.key vals 638241, leaf pages 1834, size pages 1896
   FIELDS:  uid id /*表中定義的二級索引明明只有uid,為什么最右邊又會出現id列呢*/

對於/**/的內容,最后解釋。

分析:

     通過root page這一行的信息得出結果再一次證實了表大小一樣。這里可能產生疑問,為什么UUID主鍵的表和自增ID的表大小一樣呢?INNODB的主鍵是聚集索引,第二索引都包含主鍵信息,主鍵越 大,表的第二索引就越大。理論上說UUID當主鍵,會使得頁面更離散,碎片越多,結果應該是test表比test_bak的表要大才對? 【UUID是有一定的順序的,不是完全隨機】。從上面的信息中很容易看到(FIELDS行):test和test_bak表他們的區別只是uid和id調換了位置,其他值都一樣。這就表明了INNODB主鍵值都包含了一樣的信息:主鍵列、事務ID,回滾指針和其他列的信息。故這2張表的主鍵占用的頁大小一樣。第2行的FIELDS信息:表明INNODB非主鍵索引都包含其主鍵信息。

再看看各個索引頁面利用率情況:都一致

View Code
  table: test/test_bak, index: PRIMARY, space id: 489, root page: 3, zip size: 0
  estimated statistics in dictionary:
    key vals: 652518, leaf pages: 4056, size pages: 4070
  real statistics:
     level 2 pages: pages=1, data=70 bytes, data/pages=0%
     level 1 pages: pages=5, data=56784 bytes, data/pages=69%
        leaf pages: recs=639759, pages=4056, data=61231681 bytes, data/pages=92%

  table: test/test_bak, index: idx_id, space id: 489, root page: 4, zip size: 0
  estimated statistics in dictionary:
    key vals: 638241, leaf pages: 1834, size pages: 1896
  real statistics:
     level 2 pages: pages=1, data=350 bytes, data/pages=2%
     level 1 pages: pages=7, data=91700 bytes, data/pages=79%
        leaf pages: recs=639759, pages=1834, data=29428914 bytes, data/pages=97%
--------------------------------------
  table: test/test, index: PRIMARY, space id: 488, root page: 3, zip size: 0
  estimated statistics in dictionary:
    key vals: 631224, leaf pages: 4056, size pages: 4078
  real statistics:
     level 2 pages: pages=1, data=611 bytes, data/pages=3%
     level 1 pages: pages=13, data=190632 bytes, data/pages=89%
        leaf pages: recs=639759, pages=4056, data=61231681 bytes, data/pages=92%

  table: test/test, index: idx_id, space id: 488, root page: 4, zip size: 0
  estimated statistics in dictionary:
    key vals: 638241, leaf pages: 1834, size pages: 1896
  real statistics:
     level 2 pages: pages=1, data=350 bytes, data/pages=2%
     level 1 pages: pages=7, data=91700 bytes, data/pages=79%
        leaf pages: recs=639759, pages=1834, data=29428914 bytes, data/pages=97%

      通過 show table status like 來查看這2張表大小也很相近,各個索引的頁面利用率也是一樣。所以對於這種情況,用字符串做主鍵還是整型ID做主鍵其實是一樣的,具體看需要用那個字段來檢索,通過主鍵來檢索只需要訪問一次索引列表就可以,而二級索引則需要2次定位(2次IO)。

總結:

      一張表里面有2個索引(一個主鍵,一個非主鍵),要是條件允許,他們索引互換,即使是字符串,就像例子里的情況一樣[ 給任意一個或則多個字段(字符串或則整型)加主鍵或則非主鍵,另一個(字符串或則ID類型)為非主鍵或則主鍵]。它們占用空間的大小都一樣。

+++++++++++++++++++++++++
上面說明UUID和自增ID可以任意當主鍵(不考慮其他情況)
+++++++++++++++++++++++++

測試二:

一般正常的情況,一張表都會大於2個索引的。所以下面開始再對例子中的表再加一個索引:add index idx_name(name)。

View Code
*************************** 1. row ***************************
       Table: testA
Create Table: CREATE TABLE `testA` (
  `uid` char(36) NOT NULL DEFAULT '',
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `status` tinyint(4) DEFAULT NULL,
  PRIMARY KEY (`uid`),
  KEY `idx_id` (`id`),/*id,uid*/
  KEY `idx_name` (`name`)/*name,uid*/
) ENGINE=InnoDB AUTO_INCREMENT=655351 DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

root@localhost : test 05:32:42>show create table testA_bak\G;
*************************** 1. row ***************************
       Table: testA_bak
Create Table: CREATE TABLE `testA_bak` (
  `uid` char(36) NOT NULL DEFAULT '',
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `status` tinyint(4) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_id` (`uid`),/*uid,id*/
  KEY `idx_name` (`name`)/*name,id*/
) ENGINE=InnoDB AUTO_INCREMENT=655351 DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

表大小:

View Code
-rw-rw---- 1 mysql mysql 8.5K 2012-09-21 11:45 testA_bak.frm
-rw-rw---- 1 mysql mysql 140M 2012-09-21 11:47 testA_bak.ibd
-rw-rw---- 1 mysql mysql 8.5K 2012-09-21 11:44 testA.frm
-rw-rw---- 1 mysql mysql 168M 2012-09-21 11:46 testA.ibd

字符串主鍵的表變大了!通過innodb_table_monitor來查看他們的具體信息:

TABLE: name test/testA, id 0 720, flags 1, columns 7, indexes 3, appr.rows 601311
  COLUMNS: uid: DATA_MYSQL DATA_NOT_NULL len 108; id: DATA_INT DATA_BINARY_TYPE DATA_NOT_NULL len 4; name: DATA_VARMYSQL len 765; status: DATA_INT DATA_BINARY_TYPE len 1; DB_ROW_ID: DATA_SYS prtype 256 len 6; DB_TRX_ID: DATA_SYS prtype 257 len 6; DB_ROLL_PTR: DATA_SYS prtype 258 len 7;
  INDEX: name PRIMARY, id 0 1391, fields 1/6, uniq 1, type 3
   root page 3, appr.key vals 601311, leaf pages 4056, size pages 4078
   FIELDS:  uid DB_TRX_ID DB_ROLL_PTR id name status
  INDEX: name idx_id, id 0 1392, fields 1/2, uniq 2, type 0
   root page 4, appr.key vals 638241, leaf pages 1834, size pages 1896
   FIELDS:  id uid
  INDEX: name idx_name, id 0 1393, fields 1/2, uniq 2, type 0
   root page 5, appr.key vals 1355, leaf pages 3590, size pages 4224
   FIELDS:  name uid
--------------------------------------
TABLE: name test/testA_bak, id 0 721, flags 1, columns 7, indexes 3, appr.rows 644406
  COLUMNS: uid: DATA_MYSQL DATA_NOT_NULL len 108; id: DATA_INT DATA_BINARY_TYPE DATA_NOT_NULL len 4; name: DATA_VARMYSQL len 765; status: DATA_INT DATA_BINARY_TYPE len 1; DB_ROW_ID: DATA_SYS prtype 256 len 6; DB_TRX_ID: DATA_SYS prtype 257 len 6; DB_ROLL_PTR: DATA_SYS prtype 258 len 7;
  INDEX: name PRIMARY, id 0 1394, fields 1/6, uniq 1, type 3
   root page 3, appr.key vals 644406, leaf pages 4056, size pages 4070
   FIELDS:  id DB_TRX_ID DB_ROLL_PTR uid name status
  INDEX: name idx_id, id 0 1395, fields 1/2, uniq 2, type 0
   root page 4, appr.key vals 638484, leaf pages 1838, size pages 1961
   FIELDS:  uid id
  INDEX: name idx_name, id 0 1396, fields 1/2, uniq 2, type 0
   root page 5, appr.key vals 808, leaf pages 2131, size pages 2412
   FIELDS:  name id

通過root page 行信息得到:前面2個索引信息大小都幾乎一致,新加的name索引差距最大。計算差距多少:

View Code
root@localhost : test 05:32:47>select (4078+1896+4224)-(4070+1961+2412);
+-----------------------------------+
| (4078+1896+4224)-(4070+1961+2412) |
+-----------------------------------+
|                              1755 |
+-----------------------------------+
1 row in set (0.00 sec)

root@localhost : test 05:45:12>select 1755*16/1024;
+--------------+
| 1755*16/1024 |
+--------------+
|      27.4219 |
+--------------+
1 row in set (0.00 sec)

剛好和表的物理文件一致。

頁面利用率:字符串的比整型的要高一點。

View Code
  table: test/testA, index: PRIMARY, space id: 490, root page: 3, zip size: 0
  estimated statistics in dictionary:
    key vals: 667728, leaf pages: 4056, size pages: 4078
  real statistics:
     level 2 pages: pages=1, data=611 bytes, data/pages=3%
     level 1 pages: pages=13, data=190632 bytes, data/pages=89%
        leaf pages: recs=639759, pages=4056, data=61231681 bytes, data/pages=92%

  table: test/testA, index: idx_id, space id: 490, root page: 4, zip size: 0
  estimated statistics in dictionary:
    key vals: 638241, leaf pages: 1834, size pages: 1896
  real statistics:
     level 2 pages: pages=1, data=350 bytes, data/pages=2%
     level 1 pages: pages=7, data=91700 bytes, data/pages=79%
        leaf pages: recs=639759, pages=1834, data=29428914 bytes, data/pages=97%

  table: test/testA, index: idx_name, space id: 490, root page: 5, zip size: 0
  estimated statistics in dictionary:
    key vals: 1355, leaf pages: 3590, size pages: 4224
  real statistics:
     level 2 pages: pages=1, data=2796 bytes, data/pages=17%
     level 1 pages: pages=34, data=295652 bytes, data/pages=53%
        leaf pages: recs=639759, pages=3590, data=49716019 bytes, data/pages=84%

  table: test/testA_bak, index: PRIMARY, space id: 491, root page: 3, zip size: 0
  estimated statistics in dictionary:
    key vals: 667728, leaf pages: 4056, size pages: 4070
  real statistics:
     level 2 pages: pages=1, data=70 bytes, data/pages=0%
     level 1 pages: pages=5, data=56784 bytes, data/pages=69%
        leaf pages: recs=639759, pages=4056, data=61231681 bytes, data/pages=92%

  table: test/testA_bak, index: idx_id, space id: 491, root page: 4, zip size: 0
  estimated statistics in dictionary:
    key vals: 638484, leaf pages: 1838, size pages: 1961
  real statistics:
     level 2 pages: pages=1, data=400 bytes, data/pages=2%
     level 1 pages: pages=8, data=91900 bytes, data/pages=70%
        leaf pages: recs=639759, pages=1838, data=29428914 bytes, data/pages=97%

  table: test/testA_bak, index: idx_name, space id: 491, root page: 5, zip size: 0
  estimated statistics in dictionary:
    key vals: 4803, leaf pages: 2131, size pages: 2412
  real statistics:
     level 2 pages: pages=1, data=501 bytes, data/pages=3%
     level 1 pages: pages=11, data=105730 bytes, data/pages=58%
        leaf pages: recs=639759, pages=2131, data=28603972 bytes, data/pages=81%

總結:

      INNODB表是索引組織的表,主鍵是聚集索引,非主鍵索引都包含主鍵信息。所以主鍵越小,會讓二級索引表空間都減少很多,也能加快寫入操作。內存可以緩存更多的數據。

測試三:(隨即字符串的測試)

     網上找到一個隨即字符串函數:

set global log_bin_trust_function_creators =1;
DELIMITER $$  
CREATE  FUNCTION `rand_string`(n int)  RETURNS varchar(255)  
    BEGIN  
      DECLARE chars_str varchar(100) DEFAULT 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';  
      DECLARE return_str varchar(255) DEFAULT '';  
  
      DECLARE i INT DEFAULT 0;  
  
      WHILE i < n DO  
        SET return_str = concat(return_str,substring(chars_str , FLOOR(1 + RAND()*62 ),1));  
        SET i = i +1;  
      END WHILE;  
      RETURN return_str;  
   END$$  
DELIMITER ; 

 新建表和數據:

View Code
mysql> show create table t1\G;
*************************** 1. row ***************************
       Table: t1
Create Table: CREATE TABLE `t1` (
  `uid` char(36) NOT NULL DEFAULT '',
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `status` tinyint(4) DEFAULT NULL,
  PRIMARY KEY (`uid`),
  KEY `idx_id` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
mysql> show create table t2\G;
*************************** 1. row ***************************
       Table: t2
Create Table: CREATE TABLE `t2` (
  `uid` char(36) NOT NULL DEFAULT '',
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `status` tinyint(4) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_uid` (`uid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

mysql> insert into t1(uid,name,status) select rand_string(36),name,status from test;
Query OK, 639759 rows affected (42 min 5.18 sec)
Records: 639759  Duplicates: 0  Warnings: 0

mysql> insert into t2(uid,name,status) select rand_string(36),name,status from test;
Query OK, 639759 rows affected (4 min 7.30 sec)
Records: 639759  Duplicates: 0  Warnings: 0

查看其物理大小:

View Code
-rw-rw---- 1 mysql mysql 8.5K 2012-09-22 01:51 t1.frm
-rw-rw---- 1 mysql mysql 144M 2012-09-22 02:34 t1.ibd
-rw-rw---- 1 mysql mysql 8.5K 2012-09-22 01:51 t2.frm
-rw-rw---- 1 mysql mysql 120M 2012-09-22 02:38 t2.ibd

根據innodb_table_monitor 信息查看:

--------------------------------------
TABLE: name test/t1, id 0 24, columns 7, indexes 2, appr.rows 627274
  COLUMNS: uid: DATA_MYSQL DATA_NOT_NULL len 108; id: DATA_INT DATA_BINARY_TYPE DATA_NOT_NULL len 4; name: DATA_VARMYSQL len 765; status: DATA_INT DATA_BINARY_TYPE len 1; DB_ROW_ID: DATA_SYS prtype 256 len 6; DB_TRX_ID: DATA_SYS prtype 257 len 6; DB_ROLL_PTR: DATA_SYS prtype 258 len 7; 
  INDEX: name PRIMARY, id 0 26, fields 1/6, uniq 1, type 3
   root page 3, appr.key vals 627274, leaf pages 5735, size pages 6592
   FIELDS:  uid DB_TRX_ID DB_ROLL_PTR id name status
  INDEX: name idx_id, id 0 27, fields 1/2, uniq 2, type 0
   root page 4, appr.key vals 638241, leaf pages 1834, size pages 1896
   FIELDS:  id uid
--------------------------------------
TABLE: name test/t2, id 0 25, columns 7, indexes 2, appr.rows 654546
  COLUMNS: uid: DATA_MYSQL DATA_NOT_NULL len 108; id: DATA_INT DATA_BINARY_TYPE DATA_NOT_NULL len 4; name: DATA_VARMYSQL len 765; status: DATA_INT DATA_BINARY_TYPE len 1; DB_ROW_ID: DATA_SYS prtype 256 len 6; DB_TRX_ID: DATA_SYS prtype 257 len 6; DB_ROLL_PTR: DATA_SYS prtype 258 len 7; 
  INDEX: name PRIMARY, id 0 28, fields 1/6, uniq 1, type 3
   root page 3, appr.key vals 654546, leaf pages 4056, size pages 4070
   FIELDS:  id DB_TRX_ID DB_ROLL_PTR uid name status
  INDEX: name idx_uid, id 0 29, fields 1/2, uniq 2, type 0
   root page 4, appr.key vals 638598, leaf pages 2588, size pages 2990
   FIELDS:  uid id

表空間差距大小:

View Code
mysql> select (6592+1896)-(4070+2990);
+-------------------------+
| (6592+1896)-(4070+2990) |
+-------------------------+
|                    1428 |
+-------------------------+
1 row in set (0.00 sec)

mysql> select 1428*16/1024;
+--------------+
| 1428*16/1024 |
+--------------+
|      22.3125 |
+--------------+
1 row in set (0.04 sec)

和物理空間大小非常相近。

繼續查看他的索引頁的利用率:

View Code
  table: test/t1, index: PRIMARY, space id: 7, root page: 3, zip size: 0
  estimated statistics in dictionary:
    key vals: 682474, leaf pages: 5735, size pages: 6592
  real statistics:
     level 2 pages: pages=1, data=1457 bytes, data/pages=8%
     level 1 pages: pages=31, data=269545 bytes, data/pages=53%
        leaf pages: recs=639759, pages=5735, data=61231681 bytes, data/pages=65%

  table: test/t1, index: idx_id, space id: 7, root page: 4, zip size: 0
  estimated statistics in dictionary:
    key vals: 638241, leaf pages: 1834, size pages: 1896
  real statistics:
     level 2 pages: pages=1, data=350 bytes, data/pages=2%
     level 1 pages: pages=7, data=91700 bytes, data/pages=79%
        leaf pages: recs=639759, pages=1834, data=29428914 bytes, data/pages=97%
---        
  table: test/t2, index: PRIMARY, space id: 8, root page: 3, zip size: 0
  estimated statistics in dictionary:
    key vals: 642378, leaf pages: 4056, size pages: 4070
  real statistics:
     level 2 pages: pages=1, data=70 bytes, data/pages=0%
     level 1 pages: pages=5, data=56784 bytes, data/pages=69%
        leaf pages: recs=639759, pages=4056, data=61231681 bytes, data/pages=92%

  table: test/t2, index: idx_uid, space id: 8, root page: 4, zip size: 0
  estimated statistics in dictionary:
    key vals: 606895, leaf pages: 2588, size pages: 2990
  real statistics:
     level 2 pages: pages=1, data=650 bytes, data/pages=3%
     level 1 pages: pages=13, data=129400 bytes, data/pages=60%
        leaf pages: recs=639759, pages=2588, data=29428914 bytes, data/pages=69%

通過leaf pages: 行信息看到,他們相當的索引差距還是比較大的。

從上面的這些信息中看到主鍵和非主鍵索引大小都不一樣,和第一個測試沖突?原因是什么呢?

解釋前需要理解INNODB聚集索引的概念以及隨機字符串的信息.

分析:

     上面插入測試數據的時候,隨即字符串主鍵的表插入效率相比有自增主鍵的表效率慢很多;之所以這樣是因為:插入的值會被隨機的放入索引中,導致分頁,磁盤隨機訪問,產生聚集索引碎片。
innodb的索引以B-tree的形式存到各個葉點上(包括data)。索引葉點頁的大小默認為16K(會存2行記錄),當有索引插入葉節點時,該葉節點至少會保留1/16的空閑空間,用於將來該葉節點的索引更新或是插入。對於順序寫入的索引,索引葉節點可以達到15/16就寫滿再起另一個頁。如果是隨機的索引寫入,會讓葉節點只達到1/2到15/16。當葉節點填充在1/2以下或是被刪除到1/2下時,該葉節點可以被繼續寫入數據繼,要是當前頁不”夠大“則會導致頁的分裂,這樣就導致存一樣的數據需要更多的頁。信息中數據都是61231681,而隨機主鍵需要5735,自增主鍵則只需要4056。

雖然自增主鍵表的第二索引(隨機字段在最左)比隨機字符串表的第二索引要大(順序字段在最左),但是相比整個條件下。主鍵的隨機性能遠大於第二索引。

既然是碎片,那就OPTIMIZE TABLE一下,結果驚奇的發現t1的各個信息都和t2的一樣。

View Code
-rw-rw---- 1 mysql mysql 8.5K 2012-09-22 03:05 t1.frm
-rw-rw---- 1 mysql mysql 120M 2012-09-22 03:08 t1.ibd
-rw-rw---- 1 mysql mysql 8.5K 2012-09-22 01:51 t2.frm
-rw-rw---- 1 mysql mysql 120M 2012-09-22 02:38 t2.ibd

TABLE: name test/t1, id 0 27, columns 7, indexes 2, appr.rows 639336
  COLUMNS: uid: DATA_MYSQL DATA_NOT_NULL len 108; id: DATA_INT DATA_BINARY_TYPE DATA_NOT_NULL len 4; name: DATA_VARMYSQL len 765; status: DATA_INT DATA_BINARY_TYPE len 1; DB_ROW_ID: DATA_SYS prtype 256 len 6; DB_TRX_ID: DATA_SYS prtype 257 len 6; DB_ROLL_PTR: DATA_SYS prtype 258 len 7;
  INDEX: name PRIMARY, id 0 31, fields 1/6, uniq 1, type 3
   root page 3, appr.key vals 639336, leaf pages 4056, size pages 4078
   FIELDS:  uid DB_TRX_ID DB_ROLL_PTR id name status
  INDEX: name idx_id, id 0 32, fields 1/2, uniq 2, type 0
   root page 4, appr.key vals 601915, leaf pages 2575, size pages 2991
   FIELDS:  id uid
--------------------------------------
TABLE: name test/t2, id 0 25, columns 7, indexes 2, appr.rows 634266
  COLUMNS: uid: DATA_MYSQL DATA_NOT_NULL len 108; id: DATA_INT DATA_BINARY_TYPE DATA_NOT_NULL len 4; name: DATA_VARMYSQL len 765; status: DATA_INT DATA_BINARY_TYPE len 1; DB_ROW_ID: DATA_SYS prtype 256 len 6; DB_TRX_ID: DATA_SYS prtype 257 len 6; DB_ROLL_PTR: DATA_SYS prtype 258 len 7;
  INDEX: name PRIMARY, id 0 28, fields 1/6, uniq 1, type 3
   root page 3, appr.key vals 634266, leaf pages 4056, size pages 4070
   FIELDS:  id DB_TRX_ID DB_ROLL_PTR uid name status
  INDEX: name idx_uid, id 0 29, fields 1/2, uniq 2, type 0
   root page 4, appr.key vals 574545, leaf pages 2588, size pages 2990
   FIELDS:  uid id
   
 
   table: test/t1, index: idx_id, space id: 10, root page: 4, zip size: 0
  estimated statistics in dictionary:
    key vals: 751587, leaf pages: 2575, size pages: 2991
  real statistics:
     level 2 pages: pages=1, data=700 bytes, data/pages=4%
     level 1 pages: pages=14, data=128750 bytes, data/pages=56%
        leaf pages: recs=639759, pages=2575, data=29428914 bytes, data/pages=69%

  table: test/t2, index: PRIMARY, space id: 8, root page: 3, zip size: 0
  estimated statistics in dictionary:
    key vals: 619056, leaf pages: 4056, size pages: 4070
  real statistics:
     level 2 pages: pages=1, data=70 bytes, data/pages=0%
     level 1 pages: pages=5, data=56784 bytes, data/pages=69%
        leaf pages: recs=639759, pages=4056, data=61231681 bytes, data/pages=92%

  table: test/t2, index: idx_uid, space id: 8, root page: 4, zip size: 0
  estimated statistics in dictionary:
    key vals: 657684, leaf pages: 2588, size pages: 2990
  real statistics:
     level 2 pages: pages=1, data=650 bytes, data/pages=3%
     level 1 pages: pages=13, data=129400 bytes, data/pages=60%
        leaf pages: recs=639759, pages=2588, data=29428914 bytes, data/pages=69%

  table: test/test, index: PRIMARY, space id: 4, root page: 3, zip size: 0
  estimated statistics in dictionary:
    key vals: 627675, leaf pages: 4056, size pages: 4078
  real statistics:
     level 2 pages: pages=1, data=611 bytes, data/pages=3%
     level 1 pages: pages=13, data=190632 bytes, data/pages=89%
        leaf pages: recs=639759, pages=4056, data=61231681 bytes, data/pages=92%

總結:

     隨機字符串的主鍵數據的寫入會有很多碎片產生,很多邏輯上相近的頁其實分布在磁盤和內存的各個地方。所以在這類表中需要經常OPTIMIZE,不過最好盡量避免這個類型的主鍵。

測試四:(二級索引如何保存主鍵信息)

     上面講的都是單列索引,要是多列主鍵和索引會怎么樣?

新建立表:

View Code
 CREATE TABLE `abc` (
  `uid` char(36) NOT NULL DEFAULT '',
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL DEFAULT '',
  `status` tinyint(4) DEFAULT NULL,
  PRIMARY KEY (`id`,`name`),
  KEY `idx_name_uid` (`name`,`uid`),
  KEY `idx_uid` (`uid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

具體信息:

TABLE: name test/abc, id 0 29, columns 7, indexes 3, appr.rows 0
  COLUMNS: uid: DATA_MYSQL DATA_NOT_NULL len 108; id: DATA_INT DATA_BINARY_TYPE DATA_NOT_NULL len 4; name: DATA_VARMYSQL DATA_NOT_NULL len 765; status: DATA_INT DATA_BINARY_TYPE len 1; DB_ROW_ID: DATA_SYS prtype 256 len 6; DB_TRX_ID: DATA_SYS prtype 257 len 6; DB_ROLL_PTR: DATA_SYS prtype 258 len 7;
  INDEX: name PRIMARY, id 0 34, fields 2/6, uniq 2, type 3
   root page 3, appr.key vals 0, leaf pages 1, size pages 1 FIELDS: id name DB_TRX_ID DB_ROLL_PTR uid status INDEX: name idx_name_uid, id 0 35, fields 2/3, uniq 3, type 0
   root page 4, appr.key vals 0, leaf pages 1, size pages 1 FIELDS: name uid id 
  INDEX: name idx_uid, id 0 36, fields 1/3, uniq 3, type 0
   root page 5, appr.key vals 0, leaf pages 1, size pages 1 FIELDS: uid id name

 分析: 不清楚點這里

     第一行 FIELDS 列是主鍵信息id name,包含了主鍵列,事務ID,回滾指針和其他列。

     第二行 FIELDS 列是idx_name_uid 組合索引,包含了主鍵的一個列(name字段)。需要把主鍵信息補全,不需要再包含name字段了,所以他存的信息是 name uid id

     第二行 FIELDS 列是idx_uid組合索引,沒有包含任何主鍵信息。需要把整個多列主鍵全部追加進來。索引他存的信息是 uid id name

 

更多的測試信息:

http://dinglin.iteye.com/ 


免責聲明!

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



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