テストプロセス
序文
インタビュー中に、スノーフレーク 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 はデータ挿入のパフォーマンスに影響しますが、これより良い解決策は今のところ見つかっていないため、パフォーマンスが多少犠牲になっても許容されます。