What Oracle Missed, We Fixed: More Performant Query Processing in Percona Server for MySQL

 

mysql

 

Percona 는 Query 처리 성능을 향상시키기 위한 방법을 지속적으로 연구하고 있습니다. 이러한 활동에는 Percona Server for MySQL 성능 회귀 테스트를 통해 성능을 지속적으로 모니터링하는 것이 포함되며, 새롭게 설계된 테스트를 통해 서버에 부담을 주고 병목 현상을 분석하여 개선 가능성을 평가합니다. 또한, 오픈소스 생태계에서 어떤 일이 일어나고 있는지 모니터링하는 것도 이 분야의 중요한 활동 중 하나입니다.

또한, 오픈소스 생태계에서 어떤 일이 일어나고 있는지 모니터링하는 것도 이 분야의 중요한 활동 중 하나입니다. 테스트 결과, 아이디어, 패치 등을 분석한 후, Percona Server for MySQL 에 적용할 수 있는지 검토하여 커뮤니티를 위한 개선으로 이어질 수 있도록 합니다.

이러한 연구 활동의 대표적인 성과 중 하나는 Percona Server for MySQL 8.0.42 및 8.4.5 에 포함된 기능입니다. 이는 Enchanced for MySQL 의 작업에서 영감을 받았습니다. Range Optimizer 가 table scan 경계를 선택하는 방식을 개선함으로써 쿼리 처리 속도를 향상시킵니다.

다음 테이블을 고려해 보겠습니다:

 

CREATE TABLE t1 (
    a INTEGER,
    b INTEGER,
    PRIMARY KEY (a)
);

CREATE TABLE t2 (
  a INTEGER,
    b INTEGER,
    PRIMARY KEY (a, b)
);

INSERT INTO t1 VALUES (1, 1), (2, 2);
INSERT INTO t2 VALUES (2, 1), (2, 2), (2, 3), (2, 4), (2, 5), …, (2, 100000000);

 

(t1 은 2개 row, t2 는 1억 개 row 을 가집니다.)

이제 다음 SELECT 쿼리를 살펴보겠습니다:

SELECT t1.b,t2.b FROM t1 JOIN t2 WHERE t1.a = t2.a AND t2.a = 2 AND t2.b >= t1.b AND t2.b <= t1.b+2;

 

SELECT 쿼리가 어떻게 실행되는지 확인해 보겠습니다:

mysql> EXPLAIN FORMAT = TREE SELECT t1.b,t2.b FROM t1 JOIN t2   WHERE t1.a = t2.a AND t2.a = 2 AND t2.b >= t1.b AND t2.b <= t1.b+2G
*************************** 1. row ***************************
EXPLAIN: -> Filter: ((t2.a = 2) and (t2.b >= '2') and (t2.b <= <cache>(('2' + 2))))  (cost=10e+6 rows=49.9e+6)
    -> Covering index range scan on t2 using PRIMARY over (a = 2 AND 2 <= b)  (cost=10e+6 rows=49.9e+6)

t2 테이블의 거의 모든 row(b >= 2인 모든 row)가 스캔된 것을 볼 수 있습니다. 이 작업이 반드시 필요한 동작일까요?

쿼리를 자세히 살펴보면 다음과 같습니다.

A. 우리가 관심 있는 것은a = 2 row 입니다.
B. 우리는 t1.a = t2.a row, 즉 t1.a = 2인 row 에만 관심이 있습니다. ‘a’ 는 t1 의 Primary Key 이므로, t1 에는 (2, 2) 데이터는 하나의 row 만 존재합니다. 다시 말해, t1 은 이 쿼리에서 const 테이블로 간주될 수 있습니다.
C. 우리는 t2 의 b 값이 t1.b 이상인, 즉 b >= 2 인 row 에만 관심이 있습니다.
D. 또한 b <= t1.b + 2, 즉 b <= 4인 row 에만 관심이 있습니다.

EXPLAIN 결과로 돌아가서, t2 테이블 스캔 중 조건 D 가 무시되었음을 알 수 있습니다. b = 4 에서 멈췄어야 하지만, 테이블 끝까지 계속됩니다.

이러한 동작은 MySQL 리팩토링작업(Commit 9a13c1c, https://github.com/percona/percona-server/commit/9a13c1c6971f4bd56d143179ecfb34cca8ecc018)으로 수행된 변경작업으로 발생합니다.
초기에는 test_quick_select() 함수가 내부적으로 const 테이블을 처리했으나, 해당 내용 커밋 이후에는 const 테이블 정보를 함수의 파라미터로 전달해야만 합니다.
하지만 get_quick_record_count() 함수는 nullptr 을 전달하므로, const 테이블 정보가 손실됩니다.

const 테이블 목록은 호출자 수준(get_quick_record_count())에서 사용 가능합니다. 해결책은 이를 test_quick_select() 에 전달하는 것입니다.

이 수정 이후에 쿼리가 어떻게 실행되는지 확인해 보겠습니다.

mysql> EXPLAIN FORMAT = TREE SELECT t1.b,t2.b FROM t1 JOIN t2   WHERE t1.a = t2.a AND t2.a = 2 AND t2.b >= t1.b AND t2.b <= t1.b+2G
*************************** 1. row ***************************
EXPLAIN: -> Filter: ((t2.a = 2) and (t2.b >= '2') and (t2.b <= <cache>(('2' + 2))))  (cost=1.33 rows=3)
    -> Covering index range scan on t2 using PRIMARY over (a = 2 AND 2 <= b <= 4)  (cost=1.33 rows=3)

이제 t2 테이블의 캔은 b=4 서 멈추고, 단 3개의 row 만 스캔되었습니다.

이 수정사항의 성능 영향을 살펴보겠습니다.

수정 전:

 

mysql> SELECT t1.b,t2.b FROM t1 JOIN t2   WHERE t1.a = t2.a AND t2.a = 2 AND t2.b >= t1.b AND t2.b <= t1.b+2;
+------+---+
| b    | b |
+------+---+
|    2 | 2 |
|    2 | 3 |
|    2 | 4 |
+------+---+
3 rows in set (12,57 sec)

 

수정 후:

mysql> SELECT t1.b,t2.b FROM t1 JOIN t2   WHERE t1.a = t2.a AND t2.a = 2 AND t2.b >= t1.b AND t2.b <= t1.b+2;
+------+---+
| b    | b |
+------+---+
|    2 | 2 |
|    2 | 3 |
|    2 | 4 |
+------+---+
3 rows in set (0,01 sec)

성능 향상이 상당합니다. 동일한 문제가 MySQL 에 보고되었지만 해결되지 않았습니다.
이 문제가 특정한 테이블과 쿼리에만 해당하지만, 이러한 예외적인 경우를 지속적으로 식별하고 해결하는 노력은 Oracle MySQL 대신 Percona Server for MySQL 을 선택하는 여러 이유 중 하나입니다.

 

 

블로그 원문 : https://www.percona.com/blog/what-oracle-missed-we-fixed-more-performant-query-processing-in-percona-server-for-mysql/  

 

 

자유롭게 댓글을 달아주세요! 언제나 환영합니다.
기타 문의:  info@neoclova.co.kr
네오클로바 기술블로그 홈 바로가기: https://neoclova.net
네오클로바 홈페이지: http://neoclova.co.kr

 

Similar Posts

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다