MySQL 정렬 원리 와 사례 상세 분석

8563 단어 mysql정렬의 원리
머리말
정렬 은 데이터베이스 의 기본 기능 으로 MySQL 도 예외 가 아니다.사용 자 는 Order by 문 구 를 통 해 지정 한 결과 집합 을 정렬 하 는 목적 을 달성 할 수 있 습 니 다.사실은 Order by 문구 뿐만 아니 라 Group by 어구,Distinct 문 구 는 모두 정렬 을 포함 합 니 다.본 고 는 먼저 SQL 이 색인 을 이용 하여 정렬 대 가 를 피 하 는 방법 을 간단하게 소개 한 다음 에 MySQL 이 정렬 을 실현 하 는 내부 원 리 를 소개 하고 정렬 과 관련 된 매개 변 수 를 소개 한다.마지막 으로 몇 가지'이상 한'정렬 예 를 제시 하여 정렬 일치 성 문 제 를 이야기 하고 현상 이 발생 하 는 본질 적 인 원인 을 설명 한다.
1.정렬 최적화 및 인덱스 사용
SQL 문장의 정렬 성능 을 최적화 하기 위해 서 는 정렬 을 피하 고 색인 을 합 리 적 으로 이용 하 는 것 이 좋 은 방법 입 니 다.색인 자체 도 질서 가 있 기 때문에 정렬 이 필요 한 필드 에 적당 한 색인 을 만 들 면 정렬 과정 을 뛰 어 넘 고 SQL 의 조회 속 도 를 높 일 수 있 습 니 다.다음은 전형 적 인 SQL 을 통 해 어떤 SQL 이 색인 을 이용 하여 정렬 을 줄 일 수 있 고 어떤 SQL 이 안 되 는 지 설명 하 겠 습 니 다.t1 표 에 색인 key 1 이 존재 한다 고 가정 합 니 다(keypart1,key_part2),key2(key2)
a.색인 을 이용 하여 정렬 된 SQL 을 피 할 수 있 습 니 다.

SELECT * FROM t1 ORDER BY key_part1,key_part2;
SELECT * FROM t1 WHERE key_part1 = constant ORDER BY key_part2;
SELECT * FROM t1 WHERE key_part1 > constant ORDER BY key_part1 ASC;
SELECT * FROM t1 WHERE key_part1 = constant1 AND key_part2 > constant2 ORDER BY key_part2;
b.색인 을 이용 하여 정렬 된 SQL 을 피 할 수 없습니다.

//          ,        
SELECT * FROM t1 ORDER BY key_part1,key_part2, key2;
 
//               ,        
SELECT * FROM t1 ORDER BY key_part2, key_part1;
 
//      ,        
SELECT * FROM t1 ORDER BY key_part1 DESC, key_part2 ASC;
 
//key_part1     ,key_part2        
SELECT * FROM t1 WHERE key_part1> constant ORDER BY key_part2;
2.정렬 이 이 루어 진 알고리즘
색인 을 이용 하여 정렬 을 피 할 수 없 는 SQL 에 대해 데이터 베 이 스 는 사용자 의 수 요 를 만족 시 키 기 위해 정렬 기능 을 스스로 실현 해 야 합 니 다.이때 SQL 의 실행 계획 에'Using filesort'가 나타 납 니 다.여기 서 주의해 야 할 것 은 filesort 가 파일 정렬 을 의미 하 는 것 이 아니 라 메모리 정렬 일 수도 있 습 니 다.이것 은 주로 sort 입 니 다.buffer_size 매개 변수 와 결과 집합 크기 가 확 정 됩 니 다.MySQL 내부 에서 정렬 을 실현 하 는 것 은 주로 3 가지 방식 이 있 는데 일반적인 정렬,정렬 최적화 와 우선 대기 열 정렬 을 포함한다.주로 3 가지 정렬 알고리즘 과 관련된다.빠 른 정렬,병합 정렬 과 정렬 이다.가설 표 구조 와 SQL 문 구 는 다음 과 같다.

CREATE TABLE t1(id int, col1 varchar(64), col2 varchar(64), col3 varchar(64), PRIMARY KEY(id),key(col1,col2));
SELECT col1,col2,col3 FROM t1 WHERE col1>100 ORDER BY col2;
a.일반적인 정렬
(1).표 t1 에서 WHERE 조건 을 만족 시 키 는 기록 획득
(2).기록 마다 기 록 된 메 인 키+정렬 키(id,col 2)를 꺼 내 sort buffer 에 넣 습 니 다.
(3).sort buffer 가 모든 조건 을 만족 시 키 는(id,col 2)쌍 을 저장 할 수 있다 면 정렬 합 니 다.그렇지 않 으 면 sort buffer 가 가득 차 면 정렬 을 하고 임시 파일 에 경화 합 니 다.(정렬 알고리즘 은 빠 른 정렬 알고리즘 을 사용 합 니 다)
(4).만약 에 정렬 에 임시 파일 이 생 긴 다 면 병합 정렬 알고리즘 을 이용 하여 임시 파일 에 기록 하 는 것 이 질서 가 있 도록 해 야 한다.
(5).상기 과정 을 반복 적 으로 수행 하고 모든 조건 을 만족 시 키 는 기록 이 정렬 에 참여 할 때 까지
(6).정렬 된(id,col 2)쌍 을 스 캔 하고 id 를 이용 하여 SELECT 가 되 돌아 올 열(col 1,col 2,col 3)을 건 져 옵 니 다.
(7).가 져 온 결과 집합 을 사용자 에 게 되 돌려 줍 니 다.
위 절 차 를 보면 파일 정렬 을 사용 할 지 여 부 는 주로 sort buffer 가 정렬 해 야 할(id,col 2)쌍 을 수용 할 수 있 는 지 여부 입 니 다.이 buffer 의 크기 는 sort 입 니 다.buffer_size 매개 변수 제어.그 밖 에 한 번 의 정렬 은 두 번 의 IO 가 필요 합 니 다.한 번 은 건 져 내기(id,col 2)이 고 두 번 째 는 건 져 내기(col 1,col 2,col 3)입 니 다.돌아 오 는 결과 집 은 col 2 로 정렬 되 기 때문에 id 는 어 지 러 운 순서 입 니 다.어 지 러 운 id 를 통 해 건 져 내기(col 1,col 2,col 3)할 때 대량의 랜 덤 IO 가 발생 합 니 다.두 번 째 MySQL 자체 의 최적화,즉 건 지기 전에 id 를 정렬 하고 버퍼 에 넣 는 것 입 니 다.이 캐 시 영역 크기 는 매개 변수 read 입 니 다.rnd_buffer_size 제어,그리고 질서 있 게 기록 을 건 져 내 고 무 작위 IO 를 순서 IO 로 전환 합 니 다.
b.정렬 최적화
일반적인 정렬 방식 은 정렬 자 체 를 제외 하고 두 번 의 IO 가 필요 하 다.최 적 화 된 정렬 방식 은 일반적인 정렬 에 비해 두 번 째 IO 를 감소 시 켰 다.sort buffer 를 넣 는 것 은(id,col 2)이 아니 라(col 1,col 2,col 3)입 니 다.sort buffer 에는 조회 에 필요 한 모든 필드 가 포함 되 어 있 기 때문에 정렬 이 완료 되면 바로 돌아 갈 수 있 으 며 2 차 로 데 이 터 를 건 지지 않 아 도 됩 니 다.이러한 방식 의 대 가 는 같은 크기 의 sort buffer 입 니 다.저장 할 수 있 는(col 1,col 2,col 3)수 는(id,col 2)보다 적 습 니 다.sort buffer 가 크 지 않 으 면 임시 파일 을 써 야 하고 추가 적 인 IO 를 만 들 수 있 습 니 다.물론 MySQL 은 인자 max 를 제공 합 니 다.length_for_sort_data,정렬 원본 이 max 보다 작 을 때 만length_for_sort_data 를 사용 할 때 정렬 방식 을 최적화 할 수 있 습 니 다.그렇지 않 으 면 일반적인 정렬 방식 만 사용 할 수 있 습 니 다.
c.우선 순위 정렬
최종 정렬 결 과 를 얻 기 위해 서 는 어떻게 든 조건 을 만족 시 키 는 모든 기록 을 정렬 해 야 돌아 갈 수 있 습 니 다.그렇다면 정렬 방식 을 최적화 하 는 것 보다 최적화 공간 이 있 을 까?5.6 버 전 은 Order by limit M,N 문 구 를 대상 으로 공간 차원 에서 최적화 시 켰 고 새로운 정렬 방식 인 우선 대기 열 을 추가 했다.이런 방식 은 쌓 기 정렬 으로 이 루어 졌 다.정렬 알고리즘 특징 은 limit M,N 과 같은 정렬 문 제 를 풀 수 있 습 니 다.모든 요소 가 정렬 에 참여 해 야 하지만 M+N 개 원 그룹의 sort buffer 공간 만 있 으 면 됩 니 다.M,N 의 작은 장면 에 대해 sort buffer 가 부족 해서 임시 파일 을 병합 하고 정렬 해 야 하 는 문제 가 발생 하지 않 습 니 다.오름차 순 에 대해 서 는 큰 지붕 더 미 를 사용 하고 최종 적 으로 쌓 인 요 소 는 가장 작은 N 개의 요 소 를 구성 하 며 내림차 순 에 대해 작은 지붕 더 미 를 사용 하여 최종 적 으로 쌓 인 요 소 는 가장 큰 N 의 요 소 를 구성 했다.
3.정렬 불일치 문제
사례 1
Mysql 이 5.5 에서 5.6 로 이전 한 후 페이지 에 중복 값 이 나타 난 것 을 발견 했다.
테스트 테이블 과 데이터:

create table t1(id int primary key, c1 int, c2 varchar(128));
insert into t1 values(1,1,'a');
insert into t1 values(2,2,'b');
insert into t1 values(3,2,'c');
insert into t1 values(4,2,'d');
insert into t1 values(5,3,'e');
insert into t1 values(6,4,'f');
insert into t1 values(7,5,'g');
각 페이지 의 3 조 기록 을 가정 하면 첫 페이지 의 limit 0,3 과 두 번 째 페이지 의 limit 3,3 조회 결 과 는 다음 과 같다.

우 리 는 id 가 4 인 이 기록 이 두 번 의 조회 에 동시에 나타 나 는 것 을 볼 수 있다.이것 은 분명히 기대 에 부합 되 지 않 고 5.5 버 전에 서 이 문제 가 없다.이 현상 이 발생 하 는 이 유 는 5.6 limit M,N 의 문 구 는 우선 대기 열 을 사용 하고 우선 대기 열 은 더미 로 이 루어 집 니 다.예 를 들 어 상기 예 order by c1 asc limit 0,3 은 크기 가 3 인 큰 정상 더 미 를 사용 해 야 합 니 다.limit 3,3 은 크기 가 6 인 큰 무 더 기 를 사용 해 야 한다.c1 이 2 인 기록 은 3 개 로 되 어 있 으 며,쌓 기 정렬 은 불안정 합 니 다(같은 key 값 에 대해 서 는 정렬 후 정렬 전의 위치 와 일치 하 는 것 을 보장 할 수 없습니다).따라서 페이지 가 중복 되 는 현상 을 초래 합 니 다.이 문 제 를 피하 기 위해 서 우 리 는 정렬 에 유일한 값 을 추가 할 수 있 습 니 다.예 를 들 어 메 인 키 id 는 유일한 것 이기 때문에 정렬 에 참여 하 는 key 값 이 다 르 도록 확보 할 수 있 습 니 다.SQL 을 다음 과 같이 쓰 십시오:

select * from t1 order by c1,id asc limit 0,3;
select * from t1 order by c1,id asc limit 3,3;
사례 2
두 개의 유사 한 검색 어 는 반환 열 을 제외 하고 모두 같 지만 정렬 결 과 는 일치 하지 않 습 니 다.
테스트 테이블 과 데이터:

create table t2(id int primary key, status int, c1 varchar(255),c2 varchar(255),c3 varchar(255),key(c1));
insert into t2 values(7,1,'a',repeat('a',255),repeat('a',255));
insert into t2 values(6,2,'b',repeat('a',255),repeat('a',255));
insert into t2 values(5,2,'c',repeat('a',255),repeat('a',255));
insert into t2 values(4,2,'a',repeat('a',255),repeat('a',255));
insert into t2 values(3,3,'b',repeat('a',255),repeat('a',255));
insert into t2 values(2,4,'c',repeat('a',255),repeat('a',255));
insert into t2 values(1,5,'a',repeat('a',255),repeat('a',255));
각각 SQL 문 구 를 실행 합 니 다:

select id,status,c1,c2 from t2 force index(c1) where c1>='b' order by status;
select id,status from t2 force index(c1) where c1>='b' order by status;
실행 결 과 는 다음 과 같 습 니 다.

둘 의 집행 계획 이 같 는 지 살 펴 보 자.

문 제 를 설명 하기 위해 서 나 는 문장 에 force index 의 hint 를 추가 하여 c1 열 색인 에 들 어 갈 수 있 도록 했다.문 구 는 c1 열 색인 을 통 해 id 를 건 져 낸 다음 표 에서 되 돌아 오 는 열 을 건 져 옵 니 다.c1 열 값 의 크기 에 따라 c1 색인 에 기 록 된 상대 위 치 는 다음 과 같 습 니 다.
(c1,id)==(b,6),(b,3),(5,c),(c,2),대응 하 는 status 값 은 각각 23324 이다.표 에서 데 이 터 를 건 져 내 고 status 에 따라 정렬 하면 상대 적 인 위치 가(6,2,b),(5,2,c),(3,3,c),(2,4,c)로 변 합 니 다.이것 이 바로 두 번 째 문 구 를 조회 하여 돌아 온 결과 입 니 다.그러면 왜 첫 번 째 조회 문(6,2,b),(5,2,c)은 순 서 를 바 꾸 는 것 입 니까?여기 서 제 가 전에 언급 한 a.일반적인 정렬 과 b.정렬 에 빨간색 이 표 시 된 부분 을 보면 이 유 를 알 수 있 습 니 다.첫 번 째 조회 로 돌아 온 열의 바이트 수가 max 를 초과 하 였 습 니 다.length_for_sort_data 로 인해 정렬 은 일반적인 정렬 을 사용 합 니 다.이러한 상황 에서 MYSQL 은 rowid 를 정렬 하고 무 작위 IO 를 순서 IO 로 바 꿉 니 다.그래서 5 는 앞 에 있 고 6 은 뒤에 있 습 니 다.두 번 째 조 회 는 최적화 정렬 을 사용 하고 두 번 째 로 데 이 터 를 찾 는 과정 이 없 으 며 정렬 후 기록 하 는 상대 적 인 위 치 를 유지 했다.첫 번 째 문장 에 대해 최적화 정렬 을 사용 하려 면 maxlength_for_sort_data 설정 을 확대 하면 됩 니 다.예 를 들 어 2048.

4.참고 문서
  • http://dev.mysql.com/doc/refman/5.6/en/order-by-optimization.html
  • http://mysql.taobao.org/monthly/2015/06/04/
  • http://ifxoxo.com/mysql_order_by.html
  • 여기 서 MySQL 정렬 원리 와 사례 에 대한 상세 한 분석 에 관 한 이 글 은 여기까지 소개 되 었 습 니 다.더 많은 MySQL 정렬 원리 와 사례 내용 은 예전 의 글 을 검색 하거나 아래 의 관련 글 을 계속 조회 하 시기 바 랍 니 다.앞으로 저 희 를 많이 사랑 해 주세요!

    좋은 웹페이지 즐겨찾기