Databases 10 min read

Why MySQL Auto‑Increment Beats UUID: Performance and Index Insights

This article investigates why MySQL recommends auto‑increment primary keys over UUIDs by building three test tables, measuring insert speeds with Spring JdbcTemplate, analyzing index structures, and discussing the performance trade‑offs and drawbacks of each approach.

Java Backend Technology
Java Backend Technology
Java Backend Technology
Why MySQL Auto‑Increment Beats UUID: Performance and Index Insights

Introduction

MySQL officially recommends using a sequential auto_increment primary key instead of UUIDs or non‑sequential Snowflake IDs. This article explores the reasons behind this recommendation.

1. MySQL and Program Instances

1.1 Build Three Tables

Three tables are created: user_auto_key (auto‑increment PK), user_uuid (UUID PK), and user_random_key (random long PK generated by the Snowflake algorithm). All other columns remain identical to isolate the effect of the primary key strategy.

Note: The random key is an 18‑digit long value without any regular pattern.

1.2 Performance Test Code

The test uses Spring Boot, JdbcTemplate, JUnit, and Hutool to insert a large number of rows into each table under identical conditions. Random data (name, email, address, etc.) is generated for realism.

@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("Execution Time");
        // auto_increment key task
        final String insertSql = "INSERT INTO user_key_auto(user_id,user_name,sex,address,city,email,state) VALUES(?,?,?,?,?,?,?)";
        List<UserKeyAuto> insertData = autoKeyTableService.getInsertData();
        stopwatch.start("Auto key task");
        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 time:" + (end1 - start1));
        stopwatch.stop();
        // UUID key task
        final String insertSql2 = "INSERT INTO user_uuid(id,user_id,user_name,sex,address,city,email,state) VALUES(?,?,?,?,?,?,?,?)";
        List<UserKeyUUID> insertData2 = uuidKeyTableService.getInsertData();
        stopwatch.start("UUID key task");
        long begin = System.currentTimeMillis();
        if (CollectionUtil.isNotEmpty(insertData2)) {
            boolean insertResult = jdbcTemplateService.insert(insertSql2, insertData2, true);
            System.out.println(insertResult);
        }
        long over = System.currentTimeMillis();
        System.out.println("UUID key time:" + (over - begin));
        stopwatch.stop();
        // Random long key task
        final String insertSql3 = "INSERT INTO user_random_key(id,user_id,user_name,sex,address,city,email,state) VALUES(?,?,?,?,?,?,?,?)";
        List<UserKeyRandom> insertData3 = randomKeyTableService.getInsertData();
        stopwatch.start("Random key task");
        long start = System.currentTimeMillis();
        if (CollectionUtil.isNotEmpty(insertData3)) {
            boolean insertResult = jdbcTemplateService.insert(insertSql3, insertData3, true);
            System.out.println(insertResult);
        }
        long end = System.currentTimeMillis();
        System.out.println("Random key time:" + (end - start));
        stopwatch.stop();
        String result = stopwatch.prettyPrint();
        System.out.println(result);
    }
}

1.3 Program Write Results

1.4 Efficiency Test Results

When the existing data volume reaches about 1.3 million rows, inserting another 100 k rows shows the performance ranking: auto_key > random_key > uuid . UUID insertion becomes the slowest, and its time sharply increases as the table grows.

2. Index Structure Comparison

2.1 Auto‑Increment ID Structure

Because auto‑increment keys are sequential, InnoDB stores each new record after the previous one. When a page reaches its fill factor, the next record starts a new page, keeping pages densely packed, minimizing random I/O, and avoiding page splits.

2.2 UUID Index Structure

UUIDs are random, so new rows may need to be inserted anywhere in the B‑tree. This causes frequent page reads from disk, random I/O, page splits, and fragmentation, leading to higher write latency.

2.3 Drawbacks of Auto‑Increment

Predictable IDs expose business growth trends when scraped.

High‑concurrency inserts contend for the auto‑increment lock, creating a hotspot.

Auto‑increment lock mode can cause performance loss; tuning innodb_autoinc_lock_mode may be required.

3. Conclusion

The blog demonstrates, through controlled experiments, that auto‑increment primary keys generally outperform UUIDs and random Snowflake IDs in insert speed and index efficiency. While UUIDs have their use cases, MySQL’s official guidance to prefer sequential keys remains the optimal choice for most scenarios.

MySQLdatabase designUUIDIndexauto_increment
Java Backend Technology
Written by

Java Backend Technology

Focus on Java-related technologies: SSM, Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading. Occasionally cover DevOps tools like Jenkins, Nexus, Docker, and ELK. Also share technical insights from time to time, committed to Java full-stack development!

0 followers
Reader feedback

How this landed with the community

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.