Mybatis の自動インクリメント ID データ挿入とスノーフレーク ID 挿入のパフォーマンスの比較


序文

インタビュー中に、スノーフレーク ID と自動インクリメント ID の間にデータを挿入する場合、どちらの方が速いですか? と質問されました。個人的にはデータベースの自己増加が最も速いと考えていますが、どれくらい速いかについては説明がありません。テストを行って速度を確認します。テスト結果は参考値です。

2. ステップを使用する

1.スノーフレークID生成ツールhutoolを導入する

コードは次のとおりです(例)。

        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.1.0</version>
        </dependency>

2. 実験で使用するテーブルを作成する

通常の自動インクリメント ID テーブルを使用します。

CREATE TABLE `a` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `name` varchar(255) DEFAULT NULL,
  `sex` int(255) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  `insertTime` datetime DEFAULT NULL,
  UNIQUE KEY `id` (`id`),
  KEY `nameindex` (`name`,`sex`,`age`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=20001 DEFAULT CHARSET=utf8;

スノーフレーク ID テーブル

CREATE TABLE `a1` (
  `id` bigint(20) DEFAULT NULL,
  `name` varchar(255) DEFAULT NULL,
  `sex` int(255) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  `insertTime` datetime DEFAULT NULL,
  UNIQUE KEY `id` (`id`),
  KEY `nameindex` (`name`,`sex`,`age`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

3. テストコード

制御層は次のとおりです。

    @RequestMapping(value = "/hello2",method = RequestMethod.GET)
    public String index3() {
    
    
        userService.insertUser1();
        //helloService.sayHello();
        // redisTemplate.opsForValue().set("aaa","xxx");
        return "xxxx";
    }

    @RequestMapping(value = "/hello3",method = RequestMethod.GET)
    public String index4() {
    
    
        userService.insertUser2();
        //helloService.sayHello();
        // redisTemplate.opsForValue().set("aaa","xxx");
        return "xxxx";
    }

サービス クラスは次のとおりです
。insertUser1 は自己インクリメント ID 挿入用、insertUser2 はスノーフレーク ID 挿入用です。

  @Override
    public void insertUser1() {
    
    
        long starTime = System.currentTimeMillis();
        for (int j = 0; j < 10; j++) {
    
    
            List<User> list = new ArrayList<>();
            for(int i = 0; i < 2000; i++) {
    
    
                User user = new User();
                Date date = new Date();
                user.setName("小红"+date.getTime());
                user.setAge(12);
                user.setSex(1);
                user.setInsertTime(date);
                list.add(user);
            }
            userDao.insertUser1(list);
        }
        System.out.println("插入总耗时:{}"+ (System.currentTimeMillis()-starTime)+"ms");
        }

    @Override
    public void insertUser2() {
    
    
        long starTime = System.currentTimeMillis();
        Snowflake snowflake = IdUtil.getSnowflake(31,31);
        for (int j = 0; j < 10; j++) {
    
    
            List<User1> list = new ArrayList<>();
            for(int i = 0; i < 2000; i++) {
    
    
                User1 user = new User1();
                Date date = new Date();
                user.setId(snowflake.nextId());
                user.setName("小红"+date.getTime());
                user.setAge(12);
                user.setSex(1);
                user.setInsertTime(date);
                list.add(user);
            }
            userDao.insertUser2(list);
        }
        System.out.println("插入总耗时:{}"+ (System.currentTimeMillis()-starTime)+"ms");
    }

IdUtil.getSnowflake(31,31) ここでの 2 つのパラメーターは workerid と datacenterid であり、この 2 つのパラメーターはマシン ID を形成します。

4.xml ステートメント

 <insert id="insertUser1" parameterType="com.example.springdemo.demo.model.User">
        insert into a
        (name,sex,age,insertTime) values
        <foreach collection="list" item="item" index="index" separator=",">
            (
            #{
    
    item.name},
            #{
    
    item.sex},
            #{
    
    item.age},
            #{
    
    item.insertTime}
            )
        </foreach>
    </insert>

    <insert id="insertUser2" parameterType="com.example.springdemo.demo.model.User1">
        insert into a1
        (id,name,sex,age,insertTime) values
        <foreach collection="list" item="item" index="index" separator=",">
            (
             #{
    
    item.id},
            #{
    
    item.name},
            #{
    
    item.sex},
            #{
    
    item.age},
            #{
    
    item.insertTime}
            )
        </foreach>

5. テストを開始する

1. 両方で 20,000 レコードを挿入する最初のテスト。
最初に自動インクリメント ID を呼び出した結果は
ここに画像の説明を挿入
次のようになります。

2023-02-20 11:26:35.003  INFO 10680 --- [nio-8008-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
2023-02-20 11:26:35.003  INFO 10680 --- [nio-8008-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2023-02-20 11:26:35.005  INFO 10680 --- [nio-8008-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 2 ms
插入总耗时:{
    
    }7710ms

Snowflake ID を再度呼び出した結果は
ここに画像の説明を挿入
次のようになります。

插入总耗时:{
    
    }7880ms

自己インクリメントはスノーフレーク ID よりも 170 ミリ秒高速です

2. 200,000 レコードを挿入して両方のテーブルをテストします。
両方のテーブルをクリアして、再度テストしてください。

truncate table a; 
truncate table a1; 

自動インクリメント ID テスト
ここに画像の説明を挿入

2023-02-20 11:39:11.374  INFO 14136 --- [nio-8008-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
2023-02-20 11:39:11.374  INFO 14136 --- [nio-8008-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2023-02-20 11:39:11.375  INFO 14136 --- [nio-8008-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 1 ms
插入总耗时:{
    
    }14814ms

Snowflake ID テストの
ここに画像の説明を挿入
テスト結果

插入总耗时:{
    
    }17030ms

自動インクリメントはスノーフレーク ID より 2216 ミリ秒高速であり、
前後に何度もテストしましたが、結果は自動インクリメント ID の方が高速でした。

要約する

1. Snowflake ID のデータベース タイプは bigint を使用し、Java タイプは long タイプを使用する必要があります。データベース タイプが bigint でない場合、次のようにエラーが報告されます。

### Error updating database.  Cause: com.mysql.cj.jdbc.exceptions.MysqlDataTruncation: Data truncation: Out of range value for column 'id' at row 1
### The error may exist in file [D:\javaTools\ideaCode\springbootdemo\target\classes\com\example\springdemo\demo\dao\UserDao.xml]
### The error may involve com.example.springdemo.demo.dao.UserDao.insertUser2-Inline
### The error occurred while setting parameters

2. 実験により、自動インクリメント ID は確かにスノーフレーク ID よりも高速であることが証明されましたが、現在のシステムは基本的に分散システムです。スノーフレーク ID を使用する理由は、ID の重複を避けるため 2.1 であり、スノーフレーク ID は で固定されています
。タイムスタンプ + マシン ID の順です。基本的にインデックスのデータ要件を満たしています。
2.2 他の業務を行うには、データを挿入してIDを返すのではなく、事前にIDを生成する必要があります。
2.3 データ セキュリティ要件。自己インクリメント ID により、ユーザーは ID を直接確認してデータ量を推測できます。
3. スノーフレーク ID はデータ挿入のパフォーマンスに影響しますが、これより良い解決策は今のところ見つかっていないため、パフォーマンスが多少犠牲になっても許容されます。

おすすめ

転載: blog.csdn.net/qq_34526237/article/details/129120749