Databases 14 min read

Why Auto‑Increment Beats UUID: MySQL Insert Performance Test

This article examines MySQL's recommendation to use auto_increment primary keys instead of UUIDs or random keys by creating three comparable tables, inserting large data sets with Spring JdbcTemplate, and analyzing insertion speed, index structure impact, and the trade‑offs of each key strategy.

Java High-Performance Architecture
Java High-Performance Architecture
Java High-Performance Architecture
Why Auto‑Increment Beats UUID: MySQL Insert Performance Test

Introduction

MySQL officially recommends using auto_increment primary keys rather than UUID or non‑sequential keys; this article analyses the reasons behind that recommendation.

1. MySQL and Test Tables

1.1 Create three tables

Three tables are created with identical columns except for the primary‑key generation strategy: user_key_auto (auto_increment), user_uuid (UUID stored as VARCHAR), and user_random_key (random long generated by Snowflake algorithm).

create table user_key_auto(
  id int unsigned not null auto_increment,
  userid BIGINT(64) not null default 0,
  user_name VARCHAR(64) not null default '',
  sex int(2) not null,
  address VARCHAR(255) not null default '',
  city VARCHAR(64) not null default '',
  email VARCHAR(64) not null default '',
  state int(6) not null default 0,
  primary key(id),
  key user_name_key(user_name)
) ENGINE=INNODB;
create table user_uuid(
  id VARCHAR(36) not null,
  user_id BIGINT(64) not null default 0,
  user_name VARCHAR(64) not null default '',
  sex int(2) not null,
  address VARCHAR(255) not null default '',
  city VARCHAR(64) not null default '',
  email VARCHAR(64) not null default '',
  state int(6) not null default 0,
  primary key(id),
  key user_name_key(user_name)
) ENGINE=INNODB;
create table user_random_key(
  id BIGINT(64) not null default 0,
  user_id BIGINT(64) not null default 0,
  user_name VARCHAR(64) not null default '',
  sex int(2) not null,
  address VARCHAR(255) not null default '',
  city VARCHAR(64) not null default '',
  email VARCHAR(64) not null default '',
  state int(6) not null default 0,
  primary key(id),
  key user_name_key(user_name)
) ENGINE=INNODB;

1.2 Test using Spring JdbcTemplate

The test uses Spring Boot, JdbcTemplate, JUnit and Hutool to insert the same amount of randomly generated data into each table and measure the execution time.

@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 execution time");
        // auto_increment test
        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 insert");
        long start1 = System.currentTimeMillis();
        if (CollectionUtil.isNotEmpty(insertData)) {
            boolean result = jdbcTemplateService.insert(insertSql, insertData, false);
            System.out.println(result);
        }
        long end1 = System.currentTimeMillis();
        System.out.println("auto key time:" + (end1 - start1));
        stopwatch.stop();
        // uuid test
        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 insert");
        long begin = System.currentTimeMillis();
        if (CollectionUtil.isNotEmpty(insertData2)) {
            boolean result = jdbcTemplateService.insert(insertSql2, insertData2, true);
            System.out.println(result);
        }
        long over = System.currentTimeMillis();
        System.out.println("UUID key time:" + (over - begin));
        stopwatch.stop();
        // random key test
        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 insert");
        long start = System.currentTimeMillis();
        if (CollectionUtil.isNotEmpty(insertData3)) {
            boolean result = jdbcTemplateService.insert(insertSql3, insertData3, true);
            System.out.println(result);
        }
        long end = System.currentTimeMillis();
        System.out.println("random key time:" + (end - start));
        stopwatch.stop();
        System.out.println(stopwatch.prettyPrint());
    }
}

1.3 Insertion Results

Insertion time for each table:

1.4 Efficiency Test Results

When the existing data reaches 1.3 million rows, inserting an additional 100 k rows shows the following performance ranking:

2. Index Structure Comparison

2.1 Auto‑increment internal structure

Because auto_increment values are sequential, InnoDB stores rows consecutively, leading to high page fill factor, minimal page splits, and fast locating of new rows.

2.2 UUID index structure

UUIDs are random; new rows may need to be inserted anywhere in the clustered index, causing random I/O, frequent page splits, and fragmentation.

2.3 Drawbacks of auto‑increment

Despite its advantages, auto_increment has some downsides:

Exposes business growth information because IDs are predictable.

High‑concurrency inserts can cause lock contention on the primary‑key hotspot.

Auto_increment lock mechanism introduces performance overhead; tuning innodb_autoinc_lock_mode can mitigate this.

Conclusion

The benchmark demonstrates that auto_increment primary keys consistently outperform UUID and random long keys for large‑scale inserts in MySQL. Following MySQL's official recommendation to use sequential primary keys yields better insert speed, lower fragmentation, and more efficient index usage, though specific scenarios may still require careful tuning.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

performancedatabasemysqlSpringBootauto_incrementuuid
Java High-Performance Architecture
Written by

Java High-Performance Architecture

Sharing Java development articles and resources, including SSM architecture and the Spring ecosystem (Spring Boot, Spring Cloud, MyBatis, Dubbo, Docker), Zookeeper, Redis, architecture design, microservices, message queues, Git, etc.

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.