UUID 作为数据库主键的 Insert 性能测试记录

UUID 作为数据库主键的 Insert 性能测试记录 #

在之前一篇 《Laravel使用UUID作为用户表主键并使用自定义用户表字段》发布之后和一个朋友的朋友聊了聊,讲到了一个我没有考虑到的UUID作为主键的问题——Insert性能问题。

朋友的朋友看法如下(有删改):

如果非要用 UUID 的话,完全可以用一个列来单独存放 UUID 的,没有必要把 UUID 设置为主键。自增主键的作用是 insert 的时候是顺序插入到磁盘里的,这样 innodb 直接插入就好了,因为索引插入要进行排序等一系列操作的,涉及到 innodb 索引的具体知识了,所以为了性能考虑,基本都是自增主键,保证顺序 而不是随机

Naïve Insert Time Test #

从一个小的测试开始:
硬件环境:

  • Core i7-8560U
  • 16GiB LPDDR3
  • SAMSUNG PM981

软件环境:

  • Laravel 5.6
  • MySQL 5.6

有兩個數據表,一個是使用 UUID 作爲主鍵的 users 表,一個是使用自增 id 作爲主鍵的 tickets 表,串行同步的方式插入 1000 條數據,相關 seed 函數和運行時間如下:

User Table with UUID as PK #

for ($i=0; $i < 1000; $i++) {
    DB::table('users')->insert(\[
        'user\_uuid' => (string) Uuid::generate(4),
        'user\_name' => str\_random(10),
        'user\_password' => bcrypt('secret'),
    \]);
}

用時 62.20 秒

php artisan db:seed --class=UsersTableSeeder  62.20s user 0.18s system 94% cpu 1:06.03 total

Ticket Table with increment id as PK #

for ($i=0; $i < 1000; $i++) {
    DB::table('tickets')->insert(\[
        'ticket\_from\_uuid' => (string) Uuid::generate(4),
        'tieket\_type' => str\_random(10),
        'ticket\_content' => bcrypt(str\_random(10)),
    \]);
}

用時 61.53 秒

php artisan db:seed --class=TicketsTableSeeder  61.53s user 0.11s system 94% cpu 1:05.09 total

看上去時間差別不是很大?懷疑是 bcrypt 函數導致的,換個方法,將 bcrypt 函數全部換爲 str_random 並將數據量提升到 5000 後重新測試:

php artisan db:seed --class=UsersTableSeeder  1.58s user 0.78s system 11% cpu 19.808 total

php artisan db:seed –class=TicketsTableSeeder 1.80s user 0.86s system 12% cpu 20.915 total


從這個小的測試我們可以看出如果不考慮容量和其他速度,單純測試單庫插入性能的話,可能對比不是很明顯,文章至此,偶然搜索了一下發現互聯網上已經有了一些非常成熟的測試對比,本着不重複發明輪子的思想,以下給出鏈接:

1.  [MySQL 使用自增ID主键和UUID 作为主键的优劣比较详细过程(从百万到千万表记录测试)](https://blog.csdn.net/mchdba/article/details/52336203)
2.  [UUID or GUID as Primary Keys? Be Careful!](https://tomharrisonjr.com/uuid-or-guid-as-primary-keys-be-careful-7b2aa3dcb439)