my sql 이 왜 uid 나 눈꽃 id 를 메 인 키 로 사용 하 는 것 을 추천 하지 않 는 지 깊이 분석 합 니 다.

선언:mysql 에서 표를 디자인 할 때 mysql 공식 추천 은 uid 나 중복 되 지 않 는 눈꽃 id(long 형 및 유일)를 사용 하지 말고 연속 적 으로 증가 하 는 키 id 를 추천 합 니 다.공식 추천 은 autoincrement,그렇다면 왜 uid 를 사용 하 는 것 을 권장 하지 않 습 니까?uid 를 사용 하 는 것 은 어떤 나 쁜 점 이 있 습 니까?이 블 로 그 는 우리 가 이 문 제 를 분석 하고 내부 의 원인 을 탐구 할 것 이다.
1:my sql 과 프로그램 인 스 턴 스
1.1:이 문 제 를 설명 하려 면 먼저 세 장의 표를 만 들 겠 습 니 다.각각 user 입 니 다.auto_key,user_uuid,user_random_key 는 자동 으로 증가 하 는 메 인 키,uid 를 메 인 키 로 하고 무 작위 key 를 메 인 키 로 하 며 다른 것 은 변 하지 않 습 니 다.제어 변수 법 에 따라 우 리 는 각 표 의 메 인 키 를 서로 다른 전략 으로 만 생 성 합 니 다.다른 필드 는 똑 같 습 니 다.그리고 표 의 삽입 속도 와 조회 속 도 를 테스트 합 니 다.
주:이곳 의 랜 덤 키 는 사실 눈꽃 알고리즘 으로 계산 한 전후 불 연속 반복 불규칙 id:18 비트 길이 의 long 값 을 말 합 니 다.
id 자동 생 성 표:

사용자 uid 테이블

무 작위 키 시트:

1.2:이론 만 있 으 면 안 되 고 프로그램 에 직접 올 라 가 spring 의 jdbcTemplate 를 사용 하여 추가 검사 테스트 를 실현 합 니 다.
기술 프레임 워 크:springboot+jdbcTemplate+junit+hutool.프로그램의 원 리 는 자신의 테스트 데이터 베 이 스 를 연결 한 다음 에 같은 환경 에서 같은 수량의 데 이 터 를 기록 하여 insert 가 삽 입 된 시간 을 분석 하여 그 효율 을 종합 하 는 것 이다.가장 진실 한 효 과 를 얻 기 위해 모든 데 이 터 는 무 작위 로 생 성 된다.예 를 들 어 이름,메 일,주 소 는 무 작위 로 생 성 된다.프로그램 이 gitee 에 업로드 되 었 습 니 다.주 소 는 글 밑 에 있 습 니 다.

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    ");


    /**
     * auto_increment key  
     */
    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("    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();


    /**
     * uudID key
     */
    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     ");
    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();


    /**
     *    long key
     */
    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("   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);
  }
1.3:프로그램 기록 결과
user_key_auto 기록 결과:

user_random_key 기록 결과:

user_uid 테이블 기록 결과:

1.4:효율 테스트 결과

기 존 데이터 양 이 130 W 일 때:10w 데 이 터 를 삽입 하면 어떤 결과 가 나 올 지 다시 한번 테스트 해 봅 시다.

이 를 통 해 알 수 있 듯 이 데 이 터 량 이 100 W 정도 일 때 uid 의 삽입 효율 이 바닥 에 있 고 뒷 순서 에 130 W 의 데 이 터 를 추 가 했 으 며 uudi 의 시간 은 또 수직 으로 떨 어 졌 다.시간 이 차지 하 는 용량 의 전체 효율 순 위 는:auto 이다.key>random_key>uid,uid 의 효율 이 가장 낮 고 데이터 양 이 비교적 많은 상황 에서 효율 이 수직 으로 떨어진다.그렇다면 왜 이런 현상 이 벌 어 졌 을 까?의문 을 가지 고 이 문 제 를 토론 합 시다.
2.uid 와 자체 증가 id 를 사용 한 색인 구조 비교
2.1:자체 증가 id 의 내부 구 조 를 사용 합 니 다.

증가 하 는 메 인 키 의 값 은 순서 이기 때문에 Innodb 는 모든 기록 을 하나의 기록 뒤에 저장 합 니 다.페이지 의 최대 충전 인자 에 도 달 했 을 때(innodb 의 기본 최대 충전 인 자 는 페이지 크기 의 15/16 이 며 1/16 의 공간 을 남 겨 두 고 나중에 수정 합 니 다):
① 다음 기록 은 새로운 페이지 에 기 록 됩 니 다.데이터 가 이런 순서 로 불 러 오 면 홈 페이지 는 순서 에 가 까 운 기록 으로 채 워 지고 페이지 의 최대 충전 율 을 높 여 페이지 의 낭비 가 없 도록 합 니 다.
② 새로 삽 입 된 줄 은 기 존의 최대 데이터 줄 다음 줄 에 있 을 것 입 니 다.my sql 포 지 셔 닝 과 주소 지정 이 빠 르 고 새 줄 의 위 치 를 계산 하기 위해 추가 적 인 소 모 를 하지 않 습 니 다.
③ 페이지 분열 과 파편 발생 을 감소 시킨다.
2.2:uid 의 색인 내부 구 조 를 사용 합 니 다.

uid 는 상대 적 으로 순서 가 증가 하 는 id 에 있어 서 규칙 적 이지 않 습 니 다.새 줄 의 값 이 반드시 이전 키 의 값 보다 크 지 않 기 때문에 innodb 는 항상 새 줄 을 색인 의 마지막 에 삽입 하 는 것 이 아니 라 새 줄 에 새로운 적당 한 위 치 를 찾 아 새로운 공간 을 분배 해 야 합 니 다.이 과정 은 많은 추가 적 인 조작 을 해 야 한다.데이터 의 순서 가 없 으 면 데이터 분포 가 어 지 러 워 지고 다음 과 같은 문 제 를 초래 할 수 있다.
①:기 록 된 대상 페이지 가 디스크 에 새로 고침 되 었 거나 캐 시 에서 제거 되 었 거나 캐 시 에 불 러 오지 않 았 을 수도 있 습 니 다.innodb 는 삽입 하기 전에 대상 페이지 를 디스크 에서 메모리 로 읽 어야 합 니 다.이 로 인해 대량의 무 작위 IO 가 발생 할 수 있 습 니 다.
②:기록 이 어 지 럽 기 때문에 innodb 는 페이지 분열 작업 을 자주 해 야 합 니 다.새로운 줄 에 공간 을 분배 하고 페이지 분열 로 인해 대량의 데 이 터 를 이동 할 수 있 습 니 다.한 번 에 삽입 하려 면 최소 세 페이지 이상 수정 해 야 합 니 다.
③:잦 은 페이지 분열 로 인해 페이지 가 희소 해 지고 불규칙 하 게 채 워 져 데이터 조각 이 생 길 수 있 습 니 다.
클 러 스 터 색인(innodb 기본 색인 형식)에 무 작위 값(uid 와 눈꽃 id)을 불 러 온 후,때때로 OPTIMEIZE TABLE 을 만들어 서 표를 재 구성 하고 페이지 의 충전 을 최적화 해 야 하기 때문에 시간 이 필요 합 니 다.
결론:innodb 를 사용 하려 면 가능 한 한 메 인 키 의 증가 순서에 따라 삽입 하고 가능 한 한 단조 로 운 증가 하 는 클 러 스 터 키 의 값 으로 새 줄 을 삽입 해 야 합 니 다.
2.3:자체 증가 id 를 사용 하 는 단점
그럼 자체 증가 하 는 id 를 사용 하 는 것 은 전혀 나 쁘 지 않 습 니까?아 닙 니 다.자체 증가 id 에 도 다음 과 같은 몇 가지 문제 가 존재 합 니 다.
①:다른 사람 이 당신 의 데이터 베 이 스 를 기어 오 르 면 데이터 뱅 크 의 자체 증가 id 에 따라 당신 의 업무 성장 정 보 를 얻 을 수 있 고 당신 의 경영 상황 을 쉽게 분석 할 수 있 습 니 다.
②:높 은 동시 다발 부하 에 대해 innodb 는 메 인 키 를 누 르 고 삽입 할 때 뚜렷 한 잠 금 경쟁 을 초래 할 수 있 고 메 인 키 의 상 계 는 경쟁 하 는 핫 이 슈 가 될 수 있다.모든 삽입 이 여기 서 발생 하기 때문에 동시 삽입 은 간극 잠 금 경쟁 을 초래 할 수 있다.
③:Auto_increment 잠 금 메커니즘 은 자체 잠 금 의 강탈 을 초래 하고 일정한 성능 손실 이 있 습 니 다.
첨부:Autoincrement 의 자물쇠 쟁탈 문제,개선 하려 면 innodbautoinc_lock_mode 설정
정리
이 블 로 그 는 먼저 시작 부분 에서 문 제 를 제기 하고 표 작성 부터 jdbcTemplate 를 사용 하여 서로 다른 id 생 성 전략 이 빅 데이터 양의 데이터 삽입 표현 을 테스트 한 다음 에 id 의 체제 가 서로 다른 my sql 의 색인 구조 와 장단 점 을 분석 하여 왜 uid 와 무 작위 로 id 가 데이터 삽입 에서 의 성능 손실 을 반복 하지 않 는 지 상세 하 게 설명 했다.실제 개발 에 서 는 my sql 의 공식 추천 에 따라 자체 증가 id 를 사용 하 는 것 이 좋 습 니 다.my sql 은 넓 고 심오 하 며 내부 에 최적화 할 만 한 점 이 많 습 니 다.
첨부:본 블 로그 demo 주소:https://gitee.com/Yrion/mysqlIdDemo
my sql 이 왜 uid 나 눈꽃 id 를 메 인 키 로 사용 하 는 것 을 추천 하지 않 는 지 깊이 분석 한 이 글 은 여기까지 소개 되 었 습 니 다.더 많은 my sql uid 나 눈꽃 id 를 메 인 키 로 하 는 내용 은 예전 의 글 을 검색 하거나 아래 의 관련 글 을 계속 조회 하 시기 바 랍 니 다.앞으로 도 많은 응원 부탁드립니다!

좋은 웹페이지 즐겨찾기