Databases 12 min read

Why MySQL Discourages UUIDs and Non‑Sequential IDs as Primary Keys: A Performance Analysis

This article investigates MySQL's recommendation to avoid UUID or random Snowflake IDs as primary keys, comparing auto‑increment, UUID, and random long keys through Java/JDBC performance tests, analyzing their insertion speed, index structure impact, and the trade‑offs of each approach.

Top Architect
Top Architect
Top Architect
Why MySQL Discourages UUIDs and Non‑Sequential IDs as Primary Keys: A Performance Analysis

MySQL officially recommends using auto_increment (sequential) primary keys instead of UUIDs or other non‑sequential identifiers. This article explores why UUIDs are discouraged by designing three tables— user_auto_key , user_uuid , and user_random_key —that differ only in their primary‑key generation strategy.

Using a controlled experiment, the author inserts identical data into each table via Spring Boot's JdbcTemplate and measures insertion time with StopWatch . The test environment includes springboot , jdbcTemplate , junit , and hutool for data generation.

The Java test code is shown below:

package com.wyq.mysqldemo;
import cn.hutool.core.collection.CollectionUtil;
import com.wyq.mysqldemo.databaseobject.UserKeyAuto;
import com.wyq.mysqldemo.databaseobject.UserKeyRandom;
import com.wyq.mysqldemo.databaseobject.UserKeyUUID;
import com.wyq.mysqldemo.diffkeytest.AutoKeyTableService;
import com.wyq.mysqldemo.diffkeytest.RandomKeyTableService;
import com.wyq.mysqldemo.diffkeytest.UUIDKeyTableService;
import com.wyq.mysqldemo.util.JdbcTemplateService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.util.StopWatch;
import java.util.List;
@SpringBootTest
class MysqlDemoApplicationTests {
    @Autowired
    private JdbcTemplateService jdbcTemplateService;
    @Autowired
    private AutoKeyTableService autoKeyTableService;
    @Autowired
    private UUIDKeyTableService uuidKeyTableService;
    @Autowired
    private RandomKeyTableService randomKeyTableService;
    @Test
    void testDBTime() {
        StopWatch stopwatch = new StopWatch("执行sql时间消耗");
        final String insertSql = "INSERT INTO user_key_auto(user_id,user_name,sex,address,city,email,state) VALUES(?,?,?,?,?,?,?)";
        List
insertData = autoKeyTableService.getInsertData();
        stopwatch.start("自动生成key表任务开始");
        long start1 = System.currentTimeMillis();
        if (CollectionUtil.isNotEmpty(insertData)) {
            boolean insertResult = jdbcTemplateService.insert(insertSql, insertData, false);
            System.out.println(insertResult);
        }
        long end1 = System.currentTimeMillis();
        System.out.println("auto key消耗的时间:" + (end1 - start1));
        stopwatch.stop();
        final String insertSql2 = "INSERT INTO user_uuid(id,user_id,user_name,sex,address,city,email,state) VALUES(?,?,?,?,?,?,?,?)";
        List
insertData2 = uuidKeyTableService.getInsertData();
        stopwatch.start("UUID的key表任务开始");
        long begin = System.currentTimeMillis();
        if (CollectionUtil.isNotEmpty(insertData)) {
            boolean insertResult = jdbcTemplateService.insert(insertSql2, insertData2, true);
            System.out.println(insertResult);
        }
        long over = System.currentTimeMillis();
        System.out.println("UUID key消耗的时间:" + (over - begin));
        stopwatch.stop();
        final String insertSql3 = "INSERT INTO user_random_key(id,user_id,user_name,sex,address,city,email,state) VALUES(?,?,?,?,?,?,?,?)";
        List
insertData3 = randomKeyTableService.getInsertData();
        stopwatch.start("随机的long值key表任务开始");
        Long start = System.currentTimeMillis();
        if (CollectionUtil.isNotEmpty(insertData)) {
            boolean insertResult = jdbcTemplateService.insert(insertSql3, insertData3, true);
            System.out.println(insertResult);
        }
        Long end = System.currentTimeMillis();
        System.out.println("随机key任务消耗时间:" + (end - start));
        stopwatch.stop();
        String result = stopwatch.prettyPrint();
        System.out.println(result);
    }
}

The test results show that with around 1.3 million existing rows, inserting 100 k new rows, the auto‑increment key is fastest, the random Snowflake key is slower, and the UUID key is the slowest; the performance gap widens as data volume grows.

Further analysis compares the internal index structures. Auto‑increment keys produce sequential clustered index entries, minimizing page splits, reducing random I/O, and keeping pages densely packed. In contrast, UUIDs are random, causing InnoDB to perform frequent page splits, random disk reads, and increased fragmentation, which degrades insert performance.

The article also notes drawbacks of auto‑increment keys: they expose business growth patterns, can become a hotspot under high concurrency due to lock contention, and suffer from auto‑increment lock overhead. Tuning innodb_autoinc_lock_mode can mitigate some of these issues.

In conclusion, for most MySQL workloads, following the official recommendation to use sequential auto‑increment primary keys yields better insert performance and storage efficiency, while UUIDs should be used only when their global uniqueness outweighs the performance cost.

javaperformanceMySQLJDBCauto-incrementUUIDdatabase indexing
Top Architect
Written by

Top Architect

Top Architect focuses on sharing practical architecture knowledge, covering enterprise, system, website, large‑scale distributed, and high‑availability architectures, plus architecture adjustments using internet technologies. We welcome idea‑driven, sharing‑oriented architects to exchange and learn together.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.