日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > 数据库 >内容正文

数据库

MySQL 使用自增ID主键和UUID 作为主键的优劣比較具体过程(从百万到千万表记录測试)...

發(fā)布時(shí)間:2025/7/14 数据库 98 豆豆
生活随笔 收集整理的這篇文章主要介紹了 MySQL 使用自增ID主键和UUID 作为主键的优劣比較具体过程(从百万到千万表记录測试)... 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

?

測(cè)試緣由

?

一個(gè)開發(fā)同事做了一個(gè)框架。里面主鍵是uuid。我跟他建議說mysql不要用uuid用自增主鍵,自增主鍵效率高,他說不一定高,我說innodb的索引特性導(dǎo)致了自增id做主鍵是效率最好的,為了拿實(shí)際的案例來說服他,所以準(zhǔn)備做一個(gè)具體的測(cè)試。

?

作為互聯(lián)網(wǎng)公司,一定實(shí)用戶表,并且用戶表UC_USER基本會(huì)有百萬記錄,所以在這個(gè)表基礎(chǔ)上準(zhǔn)測(cè)試數(shù)據(jù)來進(jìn)行測(cè)試。

?

???????? 測(cè)試過程是眼下我想到的多方位的經(jīng)常使用的幾種類型的sql進(jìn)行測(cè)試。當(dāng)然可能不太完好。歡迎大家留言提出更加完好的測(cè)試方案或者測(cè)試sql語(yǔ)句。

?

?

?

1、準(zhǔn)備表以及數(shù)據(jù)

UC_USER,自增ID為主鍵,表結(jié)構(gòu)相似例如以下:

CREATE?TABLE?`UC_USER`?(
??`ID`?bigint(20)?NOT?NULL?AUTO_INCREMENT?COMMENT?'主鍵',
??`USER_NAME`?varchar(100)?DEFAULT?NULL?COMMENT?'username',
??`USER_PWD`?varchar(200)?DEFAULT?NULL?COMMENT?'password',
??`BIRTHDAY`?datetime?DEFAULT?NULL?COMMENT?'生日',
??`NAME`?varchar(200)?DEFAULT?NULL?COMMENT?'姓名',
??`USER_ICON`?varchar(500)?DEFAULT?NULL?COMMENT?'頭像圖片',
??`SEX`?char(1)?DEFAULT?NULL?COMMENT?'性別,?1:男,2:女。3:保密',
??`NICKNAME`?varchar(200)?DEFAULT?NULL?COMMENT?'昵稱',
??`STAT`?varchar(10)?DEFAULT?NULL?COMMENT?'用戶狀態(tài)。01:正常,02:凍結(jié)',
??`USER_MALL`?bigint(20)?DEFAULT?NULL?COMMENT?'當(dāng)前所屬M(fèi)ALL',
??`LAST_LOGIN_DATE`?datetime?DEFAULT?NULL?COMMENT?'最后登錄時(shí)間',
??`LAST_LOGIN_IP`?varchar(100)?DEFAULT?NULL?COMMENT?'最后登錄IP',
??`SRC_OPEN_USER_ID`?bigint(20)?DEFAULT?NULL?COMMENT?'來源的聯(lián)合登錄',
??`EMAIL`?varchar(200)?DEFAULT?NULL?COMMENT?'郵箱',
??`MOBILE`?varchar(50)?DEFAULT?NULL?COMMENT?'手機(jī)',
??`IS_DEL`?char(1)?DEFAULT?'0'?COMMENT?'是否刪除',
??`IS_EMAIL_CONFIRMED`?char(1)?DEFAULT?'0'?COMMENT?'是否綁定郵箱',
??`IS_PHONE_CONFIRMED`?char(1)?DEFAULT?'0'?COMMENT?'是否綁定手機(jī)',
??`CREATER`?bigint(20)?DEFAULT?NULL?COMMENT?'創(chuàng)建人',
??`CREATE_DATE`?datetime?DEFAULT?CURRENT_TIMESTAMP?COMMENT?'注冊(cè)時(shí)間',
??`UPDATE_DATE`?datetime?DEFAULT?CURRENT_TIMESTAMP?COMMENT?'改動(dòng)日期',
??`PWD_INTENSITY`?char(1)?DEFAULT?NULL?COMMENT?'password強(qiáng)度',
??`MOBILE_TGC`?char(64)?DEFAULT?NULL?COMMENT?'手機(jī)登錄標(biāo)識(shí)',
??`MAC`?char(64)?DEFAULT?NULL?COMMENT?'mac地址',
??`SOURCE`?char(1)?DEFAULT?'0'?COMMENT?'1:WEB,2:IOS,3:ANDROID,4:WIFI,5:管理系統(tǒng),?0:未知',
??`ACTIVATE`?char(1)?DEFAULT?'1'?COMMENT?'激活,1:激活。0:未激活',
??`ACTIVATE_TYPE`?char(1)?DEFAULT?'0'?COMMENT?'激活類型,0:自己主動(dòng),1:手動(dòng)',
??PRIMARY?KEY?(`ID`),
??UNIQUE?KEY?`USER_NAME`?(`USER_NAME`),
??KEY?`MOBILE`?(`MOBILE`),
??KEY?`IDX_MOBILE_TGC`?(`MOBILE_TGC`,`ID`),
??KEY?`IDX_EMAIL`?(`EMAIL`,`ID`),
??KEY?`IDX_CREATE_DATE`?(`CREATE_DATE`,`ID`),
??KEY?`IDX_UPDATE_DATE`?(`UPDATE_DATE`)
)?ENGINE=InnoDB?AUTO_INCREMENT=7122681?DEFAULT?CHARSET=utf8?COMMENT='用戶表'

?

?

?

UC_USER_PK_VARCHAR表,字符串ID為主鍵,採(cǎi)用uuid

CREATE?TABLE?`UC_USER_PK_VARCHAR_1`?(
??`ID`?varchar(36)?CHARACTER?SET?utf8mb4?NOT?NULL?DEFAULT?'0'?COMMENT?'主鍵',
??`USER_NAME`?varchar(100)?DEFAULT?NULL?COMMENT?'username',
??`USER_PWD`?varchar(200)?DEFAULT?NULL?COMMENT?'password',
??`BIRTHDAY`?datetime?DEFAULT?NULL?COMMENT?'生日',
??`NAME`?varchar(200)?DEFAULT?NULL?COMMENT?'姓名',
??`USER_ICON`?varchar(500)?DEFAULT?NULL?COMMENT?'頭像圖片',
??`SEX`?char(1)?DEFAULT?NULL?COMMENT?'性別,?1:男,2:女。3:保密',
??`NICKNAME`?varchar(200)?DEFAULT?NULL?COMMENT?'昵稱',
??`STAT`?varchar(10)?DEFAULT?NULL?COMMENT?'用戶狀態(tài)。01:正常。02:凍結(jié)',
??`USER_MALL`?bigint(20)?DEFAULT?NULL?COMMENT?'當(dāng)前所屬M(fèi)ALL',
??`LAST_LOGIN_DATE`?datetime?DEFAULT?NULL?COMMENT?'最后登錄時(shí)間',
??`LAST_LOGIN_IP`?varchar(100)?DEFAULT?NULL?COMMENT?'最后登錄IP',
??`SRC_OPEN_USER_ID`?bigint(20)?DEFAULT?NULL?COMMENT?'來源的聯(lián)合登錄',
??`EMAIL`?varchar(200)?DEFAULT?NULL?COMMENT?'郵箱',
??`MOBILE`?varchar(50)?DEFAULT?NULL?COMMENT?'手機(jī)',
??`IS_DEL`?char(1)?DEFAULT?'0'?COMMENT?'是否刪除',
??`IS_EMAIL_CONFIRMED`?char(1)?DEFAULT?'0'?COMMENT?'是否綁定郵箱',
??`IS_PHONE_CONFIRMED`?char(1)?DEFAULT?'0'?COMMENT?'是否綁定手機(jī)',
??`CREATER`?bigint(20)?DEFAULT?NULL?COMMENT?'創(chuàng)建人',
??`CREATE_DATE`?datetime?DEFAULT?CURRENT_TIMESTAMP?COMMENT?'注冊(cè)時(shí)間',
??`UPDATE_DATE`?datetime?DEFAULT?CURRENT_TIMESTAMP?COMMENT?'改動(dòng)日期',
??`PWD_INTENSITY`?char(1)?DEFAULT?NULL?COMMENT?'password強(qiáng)度',
??`MOBILE_TGC`?char(64)?DEFAULT?NULL?COMMENT?'手機(jī)登錄標(biāo)識(shí)',
??`MAC`?char(64)?DEFAULT?NULL?COMMENT?'mac地址',
??`SOURCE`?char(1)?DEFAULT?'0'?COMMENT?'1:WEB,2:IOS,3:ANDROID,4:WIFI,5:管理系統(tǒng),?0:未知',
??`ACTIVATE`?char(1)?DEFAULT?'1'?COMMENT?'激活,1:激活,0:未激活',
??`ACTIVATE_TYPE`?char(1)?DEFAULT?'0'?COMMENT?'激活類型,0:自己主動(dòng)。1:手動(dòng)',
??PRIMARY?KEY?(`ID`),
??UNIQUE?KEY?`USER_NAME`?(`USER_NAME`),
??KEY?`MOBILE`?(`MOBILE`),
??KEY?`IDX_MOBILE_TGC`?(`MOBILE_TGC`,`ID`),
??KEY?`IDX_EMAIL`?(`EMAIL`,`ID`),
??KEY?`IDX_CREATE_DATE`?(`CREATE_DATE`,`ID`),
??KEY?`IDX_UPDATE_DATE`?(`UPDATE_DATE`)
)?ENGINE=InnoDB?DEFAULT?CHARSET=utf8?COMMENT='用戶表';

?

?

?

?

2、500W數(shù)據(jù)測(cè)試

2.1 錄入500W數(shù)據(jù)。自增ID節(jié)省一半磁盤空間

確定兩個(gè)表數(shù)據(jù)量

# 自增id為主鍵的表

mysql> select count(1) from UC_USER;

+----------+

| count(1) |

+----------+

|? 5720112 |

+----------+

1 row in set (0.00 sec)

?

mysql>

?

# uuid為主鍵的表

mysql> select count(1) from UC_USER_PK_VARCHAR_1;

+----------+

| count(1) |

+----------+

|? 5720112 |

+----------+

1 row in set (1.91 sec)

?

占領(lǐng)的空間容量來看,自增ID比UUID小一半左右。

主鍵類型

數(shù)據(jù)文件大小

占領(lǐng)容量

自增ID

-rw-rw---- 1 mysql mysql 2.5G Aug 11 18:29 UC_USER.ibd

2.5 G

UUID

-rw-rw---- 1 mysql mysql 5.4G Aug 15 15:11 UC_USER_PK_VARCHAR_1.ibd

5.4 G

?

?

?

2.2 單個(gè)數(shù)據(jù)走索引查詢,自增iduuid相差不大

主鍵類型

SQL語(yǔ)句

運(yùn)行時(shí)間 (秒)

自增ID

SELECT SQL_NO_CACHE t.* FROM test.`UC_USER` t WHERE t.`MOBILE` ='14782121512';

0.118

?

?

?

UUID

SELECT SQL_NO_CACHE t.* FROM test.`UC_USER_PK_VARCHAR_1` t WHERE t.`MOBILE` ='14782121512';

0.117

?

?

?

自增ID

SELECT SQL_NO_CACHE t.* FROM test.`UC_USER` t WHERE t.`MOBILE` IN( '14782121512','13761460105');

0.049

UUID

SELECT SQL_NO_CACHE t.* FROM test.`UC_USER_PK_VARCHAR_1` t WHERE t.`MOBILE` IN('14782121512','13761460105');

0.040

?

?

?

自增ID

SELECT SQL_NO_CACHE t.* FROM test.`UC_USER` t WHERE t.`CREATE_DATE`='2013-11-24 10:26:36' ;

0.139

UUID

SELECT SQL_NO_CACHE t.* FROM test.`UC_USER_PK_VARCHAR_1` t WHERE t.`CREATE_DATE`='2013-11-24 10:26:43' ;

0.126

?

?

?

2.3 范圍like查詢,自增ID性能優(yōu)于UUID

主鍵類型

SQL語(yǔ)句

運(yùn)行時(shí)間 (秒)

?

(1)模糊范圍查詢1000條數(shù)據(jù),自增ID性能要好于UUID

自增ID

SELECT SQL_NO_CACHE t.* FROM test.`UC_USER` t WHERE t.`MOBILE` LIKE '147%' LIMIT 1000;

1.784

UUID

SELECT SQL_NO_CACHE t.* FROM test.`UC_USER_PK_VARCHAR_1` t WHERE t.`MOBILE` LIKE '147%' LIMIT 1000;

3.196

?

(2)日期范圍查詢20條數(shù)據(jù),自增ID略微弱于UUID

自增ID

SELECT SQL_NO_CACHE t.* FROM test.`UC_USER` t WHERE t.`CREATE_DATE` > '2016-08-01 10:26:36' ORDER BY t.`UPDATE_DATE` DESC LIMIT 20;

0.601

UUID

SELECT SQL_NO_CACHE t.* FROM test.`UC_USER_PK_VARCHAR_1` t WHERE t.`CREATE_DATE` > '2016-08-01 10:26:36' ORDER BY t.`UPDATE_DATE` DESC LIMIT 20;

0.543

?

(3)范圍查詢200條數(shù)據(jù),自增ID性能要好于UUID

自增ID

SELECT SQL_NO_CACHE t.* FROM test.`UC_USER` t WHERE t.`CREATE_DATE` > '2016-07-01 10:26:36' ORDER BY t.`UPDATE_DATE` DESC LIMIT 200;

2.314

UUID

SELECT SQL_NO_CACHE t.* FROM test.`UC_USER_PK_VARCHAR_1` t WHERE t.`CREATE_DATE` > '2016-07-01 10:26:36' ORDER BY t.`UPDATE_DATE` DESC LIMIT 200;

3.229

?

范圍查詢總數(shù)量。自增ID要好于UUID

自增ID

SELECT SQL_NO_CACHE COUNT(1) FROM test.`UC_USER` t WHERE t.`CREATE_DATE` > '2016-07-01 10:26:36'? ;

0.514

UUID

SELECT SQL_NO_CACHE COUNT(1) FROM test.`UC_USER_PK_VARCHAR_1` t WHERE t.`CREATE_DATE` > '2016-07-01 10:26:36'? ;

1.092

?

?

?

PS:在有緩存的情況下。兩者運(yùn)行效率沒有相差非常小。

?

?

?

2.4 寫入測(cè)試。自增IDUUID4

主鍵類型

SQL語(yǔ)句

運(yùn)行時(shí)間 (秒)

?

?

?

?

?

自增ID

UPDATE test.`UC_USER` t SET t.`MOBILE_TGC`='T2' WHERE t.`CREATE_DATE` > '2016-05-03 10:26:36' AND t.`CREATE_DATE` <'2016-05-04 00:00:00'? ;

1.419 ?

UUID

UPDATE test.`UC_USER_PK_VARCHAR_1` t SET t.`MOBILE_TGC`='T2' WHERE t.`CREATE_DATE` > '2016-05-03 10:26:36' AND t.`CREATE_DATE` <'2016-05-04 00:00:00'? ;

5.639

?

?

?

自增ID

INSERT INTO test.`UC_USER`(?? ID,?? `USER_NAME`,?? `USER_PWD`,?? `BIRTHDAY`,?? `NAME`,?? `USER_ICON`,?? `SEX`,?? `NICKNAME`,?? `STAT`,?? `USER_MALL`,?? `LAST_LOGIN_DATE`,?? `LAST_LOGIN_IP`,?? `SRC_OPEN_USER_ID`,?? `EMAIL`,?? `MOBILE`,?? `IS_DEL`,?? `IS_EMAIL_CONFIRMED`,?? `IS_PHONE_CONFIRMED`,?? `CREATER`,?? `CREATE_DATE`,?? `UPDATE_DATE`,?? `PWD_INTENSITY`,?? `MOBILE_TGC`,?? `MAC`,?? `SOURCE`,?? `ACTIVATE`,?? `ACTIVATE_TYPE` ) SELECT?????? NULL,??? CONCAT('110',`USER_NAME`,8),?? `USER_PWD`,?? `BIRTHDAY`,?? `NAME`,?? `USER_ICON`,?? `SEX`,?? `NICKNAME`,?? `STAT`,?? `USER_MALL`,?? `LAST_LOGIN_DATE`,?? `LAST_LOGIN_IP`,?? `SRC_OPEN_USER_ID`,?? `EMAIL`, CONCAT('110',TRIM(`MOBILE`)),?? `IS_DEL`,?? `IS_EMAIL_CONFIRMED`,?? `IS_PHONE_CONFIRMED`,?? `CREATER`,?? `CREATE_DATE`,?? `UPDATE_DATE`,?? `PWD_INTENSITY`,?? `MOBILE_TGC`,?? `MAC`,?? `SOURCE`,?? `ACTIVATE`,?? `ACTIVATE_TYPE` FROM `test`.`UC_USER_1` LIMIT 100;

0.105

UUID

INSERT INTO test.`UC_USER_PK_VARCHAR_1`(??? ID,?? `USER_NAME`,?? `USER_PWD`,?? `BIRTHDAY`,?? `NAME`,?? `USER_ICON`,?? `SEX`,?? `NICKNAME`,?? `STAT`,?? `USER_MALL`,?? `LAST_LOGIN_DATE`,?? `LAST_LOGIN_IP`,?? `SRC_OPEN_USER_ID`,?? `EMAIL`,?? `MOBILE`,?? `IS_DEL`,?? `IS_EMAIL_CONFIRMED`,?? `IS_PHONE_CONFIRMED`,?? `CREATER`,?? `CREATE_DATE`,?? `UPDATE_DATE`,?? `PWD_INTENSITY`,?? `MOBILE_TGC`,?? `MAC`,?? `SOURCE`,?? `ACTIVATE`,?? `ACTIVATE_TYPE` ) SELECT???????? UUID(),?? CONCAT('110',`USER_NAME`,8),?? `USER_PWD`,?? `BIRTHDAY`,?? `NAME`,?? `USER_ICON`,?? `SEX`,?? `NICKNAME`,?? `STAT`,?? `USER_MALL`, ??`LAST_LOGIN_DATE`,?? `LAST_LOGIN_IP`,?? `SRC_OPEN_USER_ID`,?? `EMAIL`, CONCAT('110',TRIM(`MOBILE`)),?? `IS_DEL`,?? `IS_EMAIL_CONFIRMED`,?? `IS_PHONE_CONFIRMED`,?? `CREATER`,?? `CREATE_DATE`,?? `UPDATE_DATE`,?? `PWD_INTENSITY`,?? `MOBILE_TGC`,?? `MAC`,?? `SOURCE`,?? `ACTIVATE`,?? `ACTIVATE_TYPE` FROM `test`.`UC_USER_1` LIMIT 100;

0.424

?

?

?

2.5、備份和恢復(fù),自增ID性能優(yōu)于UUID

主鍵類型

SQL語(yǔ)句

運(yùn)行時(shí)間 (秒)

?

Mysqldump備份

自增ID

time mysqldump -utim -ptimgood -h192.168.121.63 test UC_USER_500> UC_USER_500.sql

28.59秒

UUID

time mysqldump -utim -ptimgood -h192.168.121.63 test UC_USER_PK_VARCHAR_500> UC_USER_PK_VARCHAR_500.sql

31.08秒

?

MySQL恢復(fù)

自增ID

time mysql? -utim -ptimgood -h192.168.121.63? test < UC_USER_500.sql

7m36.601s

UUID

time mysql? -utim -ptimgood -h192.168.121.63? test < UC_USER_PK_VARCHAR_500.sql

9m42.472s

?

?

?

?

?

?

?

3500W總結(jié)

在500W記錄表的測(cè)試下:

(1)??????普通單條或者20條左右的記錄檢索,uuid為主鍵的相差不大差點(diǎn)兒效率同樣;

(2)??????可是范圍查詢特別是上百成千條的記錄查詢,自增id的效率要大于uuid。

(3)??????在范圍查詢做統(tǒng)計(jì)匯總的時(shí)候,自增id的效率要大于uuid;

(4)??????在存儲(chǔ)上面,自增id所占的存儲(chǔ)空間是uuid的1/2;

(5)??????在備份恢復(fù)上,自增ID主鍵略微優(yōu)于UUID。

?

?

?

41000W數(shù)據(jù)測(cè)試

4.1 錄入1000W數(shù)據(jù)記錄,看存儲(chǔ)空間

# 自增id為主鍵的表

mysql> use test;

Database changed

mysql> select count(1) from UC_USER_1;

+----------+

| count(1) |

+----------+

| 10698102 |

+----------+

1 row in set (27.42 sec)

?

# uuid為主鍵的表

mysql> select count(1) from UC_USER_PK_VARCHAR_1;

+----------+

| count(1) |

+----------+

| 10698102 |

+----------+

1 row in set (0.00 sec)

?

mysql>

?

?

占領(lǐng)的空間容量來看。自增ID比UUID小一半左右:

主鍵類型

數(shù)據(jù)文件大小

占領(lǐng)容量?

自增ID

-rw-rw---- 1 mysql mysql 4.2G Aug 20 23:08 UC_USER_1.ibd

4.2 G

UUID

-rw-rw---- 1 mysql mysql 8.8G Aug 20 18:20 UC_USER_PK_VARCHAR_1.ibd

8.8 G

?

?

?

4.2 單個(gè)數(shù)據(jù)走索引查詢。自增id uuid效率比是:(2~3):1

主鍵類型

SQL語(yǔ)句

運(yùn)行時(shí)間 (秒)

?

單條記錄查詢

自增ID

SELECT SQL_NO_CACHE t.* FROM test.`UC_USER_1` t WHERE t.`MOBILE` ='14782121512';

0.069

UUID

SELECT SQL_NO_CACHE t.* FROM test.`UC_USER_PK_VARCHAR_1` t WHERE t.`MOBILE` ='14782121512';

0.274

?

小范圍查詢

自增ID

SELECT SQL_NO_CACHE t.* FROM test.`UC_USER_1` t WHERE t.`MOBILE` IN( '14782121512','13761460105');

0.050

UUID

SELECT SQL_NO_CACHE t.* FROM test.`UC_USER_PK_VARCHAR_1` t WHERE t.`MOBILE` IN('14782121512','13761460105');

0.151

?

依據(jù)日期查詢

自增ID

SELECT SQL_NO_CACHE t.* FROM test.`UC_USER_1` t WHERE t.`CREATE_DATE`='2013-11-24 10:26:36' ;

0.269

UUID

SELECT SQL_NO_CACHE t.* FROM test.`UC_USER_PK_VARCHAR_1` t WHERE t.`CREATE_DATE`='2013-11-24 10:26:43' ;

0.810

?

?

?

4.3 范圍like查詢,自增ID性能優(yōu)于UUID,比值(1.5~2)1

主鍵類型

SQL語(yǔ)句

運(yùn)行時(shí)間 (秒)

?

(1)模糊范圍查詢1000條數(shù)據(jù),自增ID性能要好于UUID

自增ID

SELECT SQL_NO_CACHE t.* FROM test.`UC_USER` t WHERE t.`MOBILE` LIKE '147%' LIMIT 1000;

2.398

UUID

SELECT SQL_NO_CACHE t.* FROM test.`UC_USER_PK_VARCHAR_1` t WHERE t.`MOBILE` LIKE '147%' LIMIT 1000;

5.872

?

(2)日期范圍查詢20條數(shù)據(jù)。自增ID略微弱于UUID

自增ID

SELECT SQL_NO_CACHE t.* FROM test.`UC_USER_1` t WHERE t.`CREATE_DATE` > '2016-08-01 10:26:36' ORDER BY t.`UPDATE_DATE` DESC LIMIT 20;

0.765

UUID

SELECT SQL_NO_CACHE t.* FROM test.`UC_USER_PK_VARCHAR_1` t WHERE t.`CREATE_DATE` > '2016-08-01 10:26:36' ORDER BY t.`UPDATE_DATE` DESC LIMIT 20;

1.090

?

(3)范圍查詢200條數(shù)據(jù),自增ID性能要好于UUID

自增ID

SELECT SQL_NO_CACHE t.* FROM test.`UC_USER_1` t WHERE t.`CREATE_DATE` > '2016-07-01 10:26:36' ORDER BY t.`UPDATE_DATE` DESC LIMIT 200;

1.569

UUID

SELECT SQL_NO_CACHE t.* FROM test.`UC_USER_PK_VARCHAR_1` t WHERE t.`CREATE_DATE` > '2016-07-01 10:26:36' ORDER BY t.`UPDATE_DATE` DESC LIMIT 200;

2.597

?

范圍查詢總數(shù)量。自增ID要好于UUID

自增ID

SELECT SQL_NO_CACHE COUNT(1) FROM test.`UC_USER_1` t WHERE t.`CREATE_DATE` > '2016-07-01 10:26:36'? ;

1.129

UUID

SELECT SQL_NO_CACHE COUNT(1) FROM test.`UC_USER_PK_VARCHAR_1` t WHERE t.`CREATE_DATE` > '2016-07-01 10:26:36'? ;

2.302

?

?

?

4.4 寫入測(cè)試,自增IDUUID效率高,比值(3~10)1

主鍵類型

SQL語(yǔ)句

運(yùn)行時(shí)間 (秒)

?

?

改動(dòng)一天的記錄

自增ID

UPDATE test.`UC_USER_1` t SET t.`MOBILE_TGC`='T2' WHERE t.`CREATE_DATE` > '2016-05-03 10:26:36' AND t.`CREATE_DATE` <'2016-05-04 00:00:00'? ;

2.685

UUID

UPDATE test.`UC_USER_PK_VARCHAR_1` t SET t.`MOBILE_TGC`='T2' WHERE t.`CREATE_DATE` > '2016-05-03 10:26:36' AND t.`CREATE_DATE` <'2016-05-04 00:00:00'? ;

26.521

?

錄入數(shù)據(jù)

自增ID

INSERT INTO test.`UC_USER_1`(?? ID,?? `USER_NAME`,?? `USER_PWD`,?? `BIRTHDAY`,?? `NAME`,?? `USER_ICON`,?? `SEX`,?? `NICKNAME`,?? `STAT`,?? `USER_MALL`,?? `LAST_LOGIN_DATE`,?? `LAST_LOGIN_IP`,?? `SRC_OPEN_USER_ID`,?? `EMAIL`,?? `MOBILE`,?? `IS_DEL`,?? `IS_EMAIL_CONFIRMED`,?? `IS_PHONE_CONFIRMED`,?? `CREATER`,?? `CREATE_DATE`,?? `UPDATE_DATE`,?? `PWD_INTENSITY`,?? `MOBILE_TGC`,?? `MAC`,?? `SOURCE`,?? `ACTIVATE`,?? `ACTIVATE_TYPE` ) SELECT?????? NULL,??? CONCAT('110',`USER_NAME`,8),?? `USER_PWD`,?? `BIRTHDAY`,?? `NAME`,?? `USER_ICON`,?? `SEX`,?? `NICKNAME`,?? `STAT`,?? `USER_MALL`,?? `LAST_LOGIN_DATE`,?? `LAST_LOGIN_IP`,?? `SRC_OPEN_USER_ID`,?? `EMAIL`, CONCAT('110',TRIM(`MOBILE`)),?? `IS_DEL`,?? `IS_EMAIL_CONFIRMED`,?? `IS_PHONE_CONFIRMED`,?? `CREATER`,?? `CREATE_DATE`,?? `UPDATE_DATE`,?? `PWD_INTENSITY`,?? `MOBILE_TGC`,?? `MAC`,?? `SOURCE`,?? `ACTIVATE`,?? `ACTIVATE_TYPE` FROM `test`.`UC_USER_1` LIMIT 100;

0.534

UUID

INSERT INTO test.`UC_USER_PK_VARCHAR_1`(??? ID,?? `USER_NAME`,?? `USER_PWD`,?? `BIRTHDAY`,?? `NAME`,?? `USER_ICON`,?? `SEX`,?? `NICKNAME`,?? `STAT`,?? `USER_MALL`,?? `LAST_LOGIN_DATE`,?? `LAST_LOGIN_IP`,?? `SRC_OPEN_USER_ID`,?? `EMAIL`,?? `MOBILE`,?? `IS_DEL`,?? `IS_EMAIL_CONFIRMED`,?? `IS_PHONE_CONFIRMED`,?? `CREATER`,?? `CREATE_DATE`,?? `UPDATE_DATE`,?? `PWD_INTENSITY`,?? `MOBILE_TGC`,?? `MAC`,?? `SOURCE`,?? `ACTIVATE`,?? `ACTIVATE_TYPE` ) SELECT???????? UUID(),?? CONCAT('110',`USER_NAME`,8),?? `USER_PWD`,?? `BIRTHDAY`,?? `NAME`,?? `USER_ICON`,?? `SEX`,?? `NICKNAME`,?? `STAT`,?? `USER_MALL`,?? `LAST_LOGIN_DATE`,?? `LAST_LOGIN_IP`,?? `SRC_OPEN_USER_ID`,?? `EMAIL`, CONCAT('110',TRIM(`MOBILE`)),?? `IS_DEL`,?? `IS_EMAIL_CONFIRMED`,?? `IS_PHONE_CONFIRMED`,?? `CREATER`,?? `CREATE_DATE`,?? `UPDATE_DATE`,?? `PWD_INTENSITY`,?? `MOBILE_TGC`,?? `MAC`,?? `SOURCE`,?? `ACTIVATE`,?? `ACTIVATE_TYPE` FROM `test`.`UC_USER_1` LIMIT 100;

1.716

?

?

?

4.5、備份和恢復(fù),自增ID性能優(yōu)于UUID

主鍵類型

SQL語(yǔ)句

運(yùn)行時(shí)間 (秒)

?

Mysqldump備份

自增ID

time mysqldump -utim -ptimgood -h192.168.121.63 test UC_USER_1> UC_USER_1.sql

0m50.548s

UUID

time mysqldump -utim -ptimgood -h192.168.121.63 test UC_USER_PK_VARCHAR_1> UC_USER_PK_VARCHAR_1.sql

0m58.590s

?

MySQL恢復(fù)

自增ID

time mysql -utim -ptimgood -h192.168.121.63 test < UC_USER_1.sql

17m30.822s

UUID

time mysql -utim -ptimgood -h192.168.121.63 test < UC_USER_PK_VARCHAR_1.sql

23m6.360s

?

?

?

?

?

?

51000W總結(jié)

在1000W記錄表的測(cè)試下:

(1)普通單條或者20條左右的記錄檢索,自增主鍵效率是uuid主鍵的2到3倍。

(2)可是范圍查詢特別是上百成千條的記錄查詢。自增id的效率要大于uuid;

(3)在范圍查詢做統(tǒng)計(jì)匯總的時(shí)候,自增id主鍵的效率是uuid主鍵1.5到2倍;

(4)在存儲(chǔ)上面,自增id所占的存儲(chǔ)空間是uuid的1/2;

(5)在寫入上面,自增ID主鍵的效率是UUID主鍵的3到10倍,相差比較明顯。特別是update小范圍之內(nèi)的數(shù)據(jù)上面。

(6)在備份恢復(fù)上。自增ID主鍵略微優(yōu)于UUID。

?

?

?

6MySQL分布式架構(gòu)的取舍

分布式架構(gòu),意味著須要多個(gè)實(shí)例中保持一個(gè)表的主鍵的唯一性。

這個(gè)時(shí)候普通的單表自增ID主鍵就不太合適。由于多個(gè)mysql實(shí)例上會(huì)遇到主鍵全局唯一性問題。

?

?

?

6.1、自增ID主鍵+步長(zhǎng)。適合中等規(guī)模的分布式場(chǎng)景

?

???????? 在每一個(gè)集群節(jié)點(diǎn)組的master上面,設(shè)置(auto_increment_increment),讓眼下每一個(gè)集群的起始點(diǎn)錯(cuò)開 1,步長(zhǎng)選擇大于將來基本不可能達(dá)到的切分集群數(shù),達(dá)到將 ID 相對(duì)分段的效果來滿足全局唯一的效果。

?

長(zhǎng)處是:實(shí)現(xiàn)簡(jiǎn)單,后期維護(hù)簡(jiǎn)單。相應(yīng)用透明。

?

缺點(diǎn)是:第一次設(shè)置相對(duì)較為復(fù)雜。由于要針對(duì)未來業(yè)務(wù)的發(fā)展而計(jì)算好足夠的步長(zhǎng);

?

規(guī)劃:

比方計(jì)劃總共N個(gè)節(jié)點(diǎn)組,那么第i個(gè)節(jié)點(diǎn)組的my.cnf的配置為:

auto_increment_offset? i

auto_increment_increment ?N

?

假如規(guī)劃48個(gè)節(jié)點(diǎn)組,N為48,如今配置第8個(gè)節(jié)點(diǎn)組。這個(gè)i為8,第8個(gè)節(jié)點(diǎn)組的my.cnf里面的配置為:

auto_increment_offset? 8

auto_increment_increment? 48

?

?

?

6.2UUID。適合小規(guī)模的分布式環(huán)境

???????? 對(duì)于InnoDB這樣的聚集主鍵類型的引擎來說。數(shù)據(jù)會(huì)依照主鍵進(jìn)行排序。由于UUID的無序性,InnoDB會(huì)產(chǎn)生巨大的IO壓力,并且由于索引和數(shù)據(jù)存儲(chǔ)在一起,字符串做主鍵會(huì)造成存儲(chǔ)空間增大一倍。

?

在存儲(chǔ)和檢索的時(shí)候,innodb會(huì)對(duì)主鍵進(jìn)行物理排序,這對(duì)auto_increment_int是個(gè)好消息,由于后一次插入的主鍵位置總是在最后。

可是對(duì)uuid來說,這卻是個(gè)壞消息。由于uuid是雜亂無章的。每次插入的主鍵位置是不確定的,可能在開頭,也可能在中間,在進(jìn)行主鍵物理排序的時(shí)候,勢(shì)必會(huì)造成大量的 IO操作影響效率,在數(shù)據(jù)量不停增長(zhǎng)的時(shí)候。特別是數(shù)據(jù)量上了千萬記錄的時(shí)候。讀寫性能下降的非常厲害。

?

長(zhǎng)處:搭建比較簡(jiǎn)單,不須要為主鍵唯一性的處理。

缺點(diǎn):占用兩倍的存儲(chǔ)空間(在云上光存儲(chǔ)一塊就要多花2倍的錢)。后期讀寫性能下降厲害。

?

?

?

?

6.3、雪花算法自造全局自增ID。適合大數(shù)據(jù)環(huán)境的分布式場(chǎng)景

由twitter發(fā)布的開源的分布式id算法snowflake(Java版本號(hào))

?

IdWorker.java:

?

package com.demo.elk;

import org.slf4j.Logger;?

import org.slf4j.LoggerFactory;

?

public class IdWorker {

???

??? protected static final Logger LOG = LoggerFactory.getLogger(IdWorker.class);

????

??? private long workerId;

??? private long datacenterId;

??? private long sequence = 0L;

?

??? private long twepoch = 1288834974657L;

?

??? private long workerIdBits = 5L;

??? private long datacenterIdBits = 5L;

??? private long maxWorkerId = -1L ^ (-1L << workerIdBits);

??? private long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);

??? private long sequenceBits = 12L;

?

??? private long workerIdShift = sequenceBits;

??? private long datacenterIdShift = sequenceBits + workerIdBits;

??? private long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;

??? private long sequenceMask = -1L ^ (-1L << sequenceBits);

?

??? private long lastTimestamp = -1L;

?

??? public IdWorker(long workerId, long datacenterId) {

??????? // sanity check for workerId

??????? if (workerId > maxWorkerId || workerId < 0) {

??????????? throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));

??????? }

??????? if (datacenterId > maxDatacenterId || datacenterId < 0) {

?????????? ?throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));

??????? }

??????? this.workerId = workerId;

??????? this.datacenterId = datacenterId;

??????? LOG.info(String.format("worker starting. timestamp left shift %d, datacenter id bits %d, worker id bits %d, sequence bits %d, workerid %d", timestampLeftShift, datacenterIdBits, workerIdBits, sequenceBits, workerId));

??? }

?

??? public synchronized long nextId() {

??????? long timestamp = timeGen();

?

??????? if (timestamp < lastTimestamp) {

??????????? LOG.error(String.format("clock is moving backwards.? Rejecting requests until %d.", lastTimestamp));

??????????? throw new RuntimeException(String.format("Clock moved backwards.? Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));

??????? }

?

??????? if (lastTimestamp == timestamp) {

??????????? sequence = (sequence + 1) & sequenceMask;

??????????? if (sequence == 0) {

??????????????? timestamp = tilNextMillis(lastTimestamp);

??????????? }

??????? } else {

??????????? sequence = 0L;

??????? }

?

??????? lastTimestamp = timestamp;

?

??????? return ((timestamp - twepoch) << timestampLeftShift) | (datacenterId << datacenterIdShift) | (workerId << workerIdShift) | sequence;

? ??}

?

??? protected long tilNextMillis(long lastTimestamp) {

??????? long timestamp = timeGen();

??????? while (timestamp <= lastTimestamp) {

??????????? timestamp = timeGen();

??????? }

??????? return timestamp;

??? }

?

??? protected long timeGen() {

??? ????return System.currentTimeMillis();

??? }

}

?

?

?

測(cè)試生成ID的測(cè)試類,IdWorkerTest.java:

package com.demo.elk;

?

import java.util.HashSet;

import java.util.Set;

?

public class IdWorkerTest {

???????? ?

??? static class IdWorkThread implements Runnable {

??????? private Set<Long> set;

??????? private IdWorker idWorker;

?

??????? public IdWorkThread(Set<Long> set, IdWorker idWorker) {

??????????? this.set = set;

??????????? this.idWorker = idWorker;

??????? }

?

??????? public void run() {

??????????? while (true) {

?????????? ?????long id = idWorker.nextId();

??????????????? System.out.println("??????????? real id:" + id);

??????????????? if (!set.add(id)) {

??????????????????? System.out.println("duplicate:" + id);

??????????????? }

??????????? }

??????? }

??? }

?

??? public static void main(String[] args) {

??????? Set<Long> set = new HashSet<Long>();

??????? final IdWorker idWorker1 = new IdWorker(0, 0);

??????? final IdWorker idWorker2 = new IdWorker(1, 0);

??????? Thread t1 = new Thread(new IdWorkThread(set, idWorker1));

? ??????Thread t2 = new Thread(new IdWorkThread(set, idWorker2));

??????? t1.setDaemon(true);

??????? t2.setDaemon(true);

??????? t1.start();

??????? t2.start();

??????? try {

??????????? Thread.sleep(30000);

??????? } catch (InterruptedException e) {

????? ??????e.printStackTrace();

??????? }

??? }

}

?

?

?

7,總結(jié)

1)單實(shí)例或者單節(jié)點(diǎn)組:

經(jīng)過500W、1000W的單機(jī)表測(cè)試,自增ID相對(duì)UUID來說。自增ID主鍵性能高于UUID。磁盤存儲(chǔ)費(fèi)用比UUID節(jié)省一半的錢。所以在單實(shí)例上或者單節(jié)點(diǎn)組上,使用自增ID作為首選主鍵。

?

2)分布式架構(gòu)場(chǎng)景:

???????? 20個(gè)節(jié)點(diǎn)組下的小型規(guī)模的分布式場(chǎng)景。為了高速實(shí)現(xiàn)部署,能夠採(cǎi)用多花存儲(chǔ)費(fèi)用、犧牲部分性能而使用UUID主鍵高速部署;

?

???????? 20到200個(gè)節(jié)點(diǎn)組的中等規(guī)模的分布式場(chǎng)景,能夠採(cǎi)用自增ID+步長(zhǎng)的較高速方案。

?

???????? 200以上節(jié)點(diǎn)組的大數(shù)據(jù)下的分布式場(chǎng)景,能夠借鑒相似twitter雪花算法構(gòu)造的全局自增ID作為主鍵。

?

?

?

總結(jié)

以上是生活随笔為你收集整理的MySQL 使用自增ID主键和UUID 作为主键的优劣比較具体过程(从百万到千万表记录測试)...的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。