카테고리 : MySQL/기술노트

세션 메모리 변수의 함정: sort_buffer_size, join_buffer_size, tmp_table_size를 크게 잡기 전에

MySQL에서 sort_buffer_size, join_buffer_size, tmp_table_size를 세션 메모리 관점에서 어떻게 해석해야 하는지와 과대 설정이 만드는 메모리·디스크·장애 리스크를 운영 관점에서 정리한다.

저자: MySQL 기술 노트 작성: 2026.06.22 약 12분 7,015자
다운로드

1. 왜 이 세 변수를 “성능 옵션”이 아니라 “장애 옵션”으로 봐야 하는가

운영 현장에서 느린 정렬, 큰 조인, 임시 테이블 증가가 보이면 많은 팀이 다음과 같이 대응한다.

  • sort_buffer_size를 키우면 ORDER BY가 빨라질 것이라고 기대한다.
  • join_buffer_size를 키우면 조인 성능이 좋아질 것이라고 생각한다.
  • tmp_table_size를 크게 잡으면 디스크 임시 테이블이 줄어들어 전체 성능이 좋아질 것이라고 판단한다.

이 접근은 절반만 맞다. 더 정확히 말하면, 국소적인 병목을 줄일 가능성은 있지만 서버 전체의 안정성을 해칠 가능성도 함께 커진다. 이유는 세 변수 모두 InnoDB buffer pool처럼 전역으로 한 번만 크게 잡히는 메모리가 아니라, 세션 실행 경로에서 필요할 때 반복적으로 잡힐 수 있는 작업 메모리이기 때문이다.

즉, 이 변수들을 크게 만드는 순간 MySQL은 “더 빠른 서버”가 되는 것이 아니라, 다음과 같은 성질을 갖는 서버로 바뀔 수 있다.

  1. 동시 세션 수가 많을수록 메모리 사용량의 상한이 급격히 불어나기 쉬운 서버
  2. 특정 시점의 정렬·조인·임시 테이블 폭주가 전체 OOM 리스크로 번질 수 있는 서버
  3. 느린 SQL의 근본 원인인 인덱스 부재, 잘못된 실행 계획, 과대한 result set을 숨기는 서버
  4. 장애 시점에만 메모리가 터지는, 평소에는 조용한 서버

핵심은 다음 한 문장으로 요약할 수 있다.

sort_buffer_size, join_buffer_size, tmp_table_size는 평균 성능보다 최악 시점의 메모리 상한을 먼저 바꾸는 변수다.

따라서 이 세 변수를 다룰 때는 “단일 쿼리가 빨라졌는가”보다 먼저 “동시성 하에서 서버가 얼마나 많은 메모리를 추가로 허용하게 되는가”를 계산해야 한다.

2. 내부 메커니즘: 왜 세션 메모리 변수는 생각보다 위험한가

MySQL의 실행기는 쿼리를 처리하면서 필요한 작업 영역을 단계별로 확보한다. 이때 모든 쿼리가 항상 같은 메모리를 쓰는 것은 아니지만, 특정 연산이 동시에 많아지면 세션별 작업 버퍼가 누적된다.

flowchart TD
    A[클라이언트 세션 시작] --> B[Optimizer가 실행 계획 선택]
    B --> C{정렬이 필요한가}
    C -- 예 --> D[sort_buffer 사용 가능]
    C -- 아니오 --> E[다음 연산으로 이동]
    D --> E
    E --> F{인덱스 없이 join하는가}
    F -- 예 --> G[join_buffer 사용 가능]
    F -- 아니오 --> H[다음 연산으로 이동]
    G --> H
    H --> I{GROUP BY DISTINCT ORDER BY 파생테이블이
임시 테이블을 요구하는가}
    I -- 예 --> J[내부 임시 테이블 생성]
    J --> K{tmp_table_size / max_heap_table_size
한도 내인가}
    K -- 예 --> L[메모리 기반 유지]
    K -- 아니오 --> M[온디스크 임시 테이블로 전환]
    I -- 아니오 --> N[결과 반환]
    L --> N
    M --> N

이 흐름에서 중요한 해석은 다음과 같다.

2.1 세 변수는 모두 “항상 예약되는 메모리”가 아니다

MySQL은 세션이 접속했다고 해서 무조건 sort_buffer_size, join_buffer_size, tmp_table_size를 한 번에 전부 점유하지 않는다. 각 버퍼는 해당 연산이 실제로 필요할 때 사용된다. 그래서 평상시 메모리 사용량만 보면 “값을 꽤 크게 잡아도 괜찮다”는 착시가 생긴다.

그러나 운영 사고는 평균이 아니라 피크에서 난다. 배치 쿼리, 리포트 쿼리, 잘못 작성된 ad-hoc SQL, failover 뒤의 재시도 폭주, 대규모 정렬이 겹치는 순간에는 여러 세션이 같은 시점에 이 작업 메모리를 요구할 수 있다. 이때 세션별 버퍼의 누적이 전역 메모리 압박으로 바뀐다.

2.2 sort_buffer_sizejoin_buffer_size는 “쿼리 하나당 한 번”이 아닐 수 있다

실무에서 자주 놓치는 점은, 정렬과 조인이 한 쿼리 안에 여러 번 등장할 수 있다는 사실이다.

  • ORDER BY가 여러 단계에서 발생할 수 있다.
  • GROUP BY와 filesort가 함께 나타날 수 있다.
  • 인덱스를 사용하지 못하는 join이 여러 테이블 사이에서 반복될 수 있다.
  • 파생 테이블(materialization)과 정렬이 동시에 개입할 수 있다.

따라서 sort_buffer_size=8M이라고 해서 쿼리 하나가 항상 8MB만 추가로 쓴다고 단정하면 안 된다. join_buffer_size도 마찬가지다. 버퍼는 세션당이면서 동시에 연산당 성격을 띨 수 있으므로, 동시 복합 연산 시 체감 메모리는 예상보다 빠르게 커진다.

2.3 tmp_table_size는 단독 해석이 위험하다

tmp_table_size는 내부 임시 테이블이 메모리에 머물 수 있는 한도를 조절하는 대표 변수로 자주 언급되지만, 실제 운영에서는 max_heap_table_size와 함께 봐야 한다. 메모리 기반 임시 테이블이 사용할 수 있는 유효 상한은 두 값 중 더 작은 쪽의 영향을 받기 때문이다.

그래서 다음과 같은 실수가 흔하다.

  • tmp_table_size만 256MB로 올려 놓고 효과가 없다고 오해함
  • max_heap_table_size는 낮게 둔 채 임시 테이블이 계속 디스크로 내려간다고 혼란스러워함
  • 반대로 두 값을 모두 크게 올려 임시 테이블 한 개가 과도한 메모리를 잡도록 방치함

즉, tmp_table_size는 “크게 잡으면 좋은 캐시”가 아니라, 메모리 임시 테이블이 어디까지 비대해질 수 있는가를 정하는 위험 한도이기도 하다.

3. 변수별 핵심 해석

3.1 sort_buffer_size: 정렬 자체보다 정렬이 필요한 실행 계획을 먼저 의심해야 한다

sort_buffer_size는 filesort 계열 정렬 작업에 사용되는 세션 버퍼다. 여기서 중요한 점은 filesort가 발생했다는 사실 자체가 반드시 나쁜 것은 아니지만, 큰 정렬이 자주 생긴다면 먼저 인덱스 설계와 result set 크기를 봐야 한다는 것이다.

운영자가 흔히 빠지는 함정은 다음과 같다.

  • ORDER BY가 느리니 sort_buffer_size를 즉시 키운다.
  • 그러나 실제 원인은 정렬할 행 수가 너무 많거나, 정렬 전에 줄일 수 있었던 집합을 너무 늦게 줄이는 쿼리 구조일 수 있다.
  • 또는 적절한 복합 인덱스로 정렬을 피할 수 있었는데, 버퍼 증설로 문제를 덮어 버린다.

sort_buffer_size를 과하게 키우면 작은 정렬에는 큰 효과가 없고, 큰 정렬이 동시 다발적으로 발생할 때만 메모리 압박이 커질 수 있다. 특히 수백~수천 세션 환경에서 정렬이 몰리면 이 값은 조용히 위험해진다.

운영 해석

  • 단일 리포트 쿼리 1개만 볼 때는 값 증설 효과가 있어 보일 수 있다.
  • 그러나 API 서버, 배치, 운영자 ad-hoc SQL이 같은 인스턴스를 공유하면 정렬 버퍼 총합이 문제로 바뀔 수 있다.
  • 정렬 성능 문제를 버퍼 증설로만 해결하려 하면, OOM 직전까지는 조용하다가 특정 시점에 급격히 무너질 수 있다.

3.2 join_buffer_size: 조인 성능 튜닝이 아니라 “인덱스를 못 탔다는 경고”인 경우가 많다

join_buffer_size는 인덱스를 효율적으로 사용하지 못하는 join 경로에서 사용될 수 있는 버퍼다. 그래서 이 값을 크게 잡는 것은 종종 “join을 빠르게 만든다”기보다 “인덱스를 못 쓰는 join을 더 오래 버티게 한다”에 가깝다.

즉, join_buffer_size가 문제의 중심에 등장했다는 사실 자체가 다음 질문을 먼저 던지게 해야 한다.

  • 조인 조건 컬럼에 적절한 인덱스가 있는가
  • 조인 순서와 필터링 순서가 합리적인가
  • 파생 테이블 materialization이 불필요하게 커지지 않는가
  • Nested Loop Join에서 outer row 수가 지나치게 많은가

join_buffer_size를 크게 잡으면 특정 비인덱스 조인이 덜 느려질 수는 있다. 그러나 이것이 좋은 구조라는 뜻은 아니다. 오히려 애플리케이션이 잘못된 SQL을 계속 내보내도 당장 폭발하지 않도록 완충하는 부작용이 생긴다.

운영 해석

  • join_buffer_size 증설은 마지막 미세 조정 단계여야 한다.
  • 이 값이 필요하다는 사실은 먼저 EXPLAIN과 인덱스 설계를 다시 보라는 신호다.
  • Aurora MySQL에서도 마찬가지로, 버퍼 증설보다 쿼리 구조 개선이 더 재현 가능하고 안전한 해결책이다.

3.3 tmp_table_size: 디스크 임시 테이블 감소와 메모리 폭주 사이의 줄타기

내부 임시 테이블은 GROUP BY, DISTINCT, ORDER BY, UNION 계열, 파생 테이블 처리 등에서 자주 등장한다. 이때 메모리 안에서 처리되면 빠를 수 있지만, 한도를 넘으면 디스크 기반 임시 테이블로 내려간다. 운영 현장에서는 이 전환 자체를 “나쁘다”로 단순화하는 경우가 많다.

그러나 더 정확한 해석은 다음과 같다.

  1. 온디스크 임시 테이블이 있다는 사실만으로 곧바로 장애는 아니다.
  2. 반대로 임시 테이블을 무조건 메모리에 오래 붙잡는 것도 좋은 일은 아니다.
  3. 실제 핵심은 얼마나 자주, 얼마나 크게, 얼마나 많은 세션이 동시에 임시 테이블을 만들고 있는가다.

tmp_table_sizemax_heap_table_size를 과도하게 키우면, 디스크 임시 테이블 수치는 좋아 보일 수 있다. 하지만 그 대가로 복수 세션이 큰 임시 테이블을 메모리에 오래 들고 있게 되어 전체 메모리 압박이 커질 수 있다. 즉, 지표 하나를 예쁘게 만들기 위해 서버 안정성을 희생하는 셈이다.

4. 메모리 상한을 어떻게 생각해야 하는가

이 세 변수의 가장 위험한 지점은 “평소에는 잘 안 보이는데, 최악 시나리오의 상한만 조용히 커진다”는 데 있다. 운영자는 다음과 같은 보수적 사고가 필요하다.

4.1 단순 합계는 실제 사용량과 다르지만, 위험 한도 추정에는 유용하다

예를 들어 다음과 같은 환경을 생각해 보자.

  • max_connections = 400
  • sort_buffer_size = 8M
  • join_buffer_size = 8M
  • tmp_table_size = 64M
  • max_heap_table_size = 64M

이 값을 보고 “모든 세션이 항상 80MB씩 쓰는 것은 아니니 괜찮다”라고 판단할 수 있다. 실제로 그 말은 맞다. 그러나 위험 평가에서는 반대로 생각해야 한다.

  • 리포트/배치 세션 일부가 큰 정렬을 동시 수행할 수 있다.
  • 비인덱스 조인이 겹치면 join_buffer_size 사용 세션이 몰릴 수 있다.
  • GROUP BY가 동시에 실행되면 메모리 임시 테이블이 누적될 수 있다.

즉, 이론상 최대치가 현실에서 100% 발생하지 않더라도, 장애 시점에는 평소보다 훨씬 높은 비율로 동시에 터질 수 있다. 그래서 세션 메모리 변수는 평균 부하 기준이 아니라, 피크 동시성 기준으로 보수적으로 설계해야 한다.

4.2 전역 메모리와 세션 메모리를 섞어 생각하면 안 된다

InnoDB buffer pool, adaptive hash, dictionary cache 같은 전역 메모리는 대체로 안정적인 큰 덩어리다. 반면 sort_buffer_size, join_buffer_size, 내부 임시 테이블은 동적으로 튀는 영역이다. 운영 문제는 대개 이 둘의 합에서 발생한다.

  • 전역 메모리를 이미 공격적으로 크게 잡아 둔 서버
  • 여기에 세션 작업 메모리까지 크게 풀어 둔 서버
  • 동시 연결과 배치 작업이 몰리는 시간대가 존재하는 서버

이 조합은 평소에는 문제없어 보이지만, 특정 시간대에만 swap, OOM killer, 커널 메모리 압박, 컨테이너 메모리 제한 초과 같은 형태로 드러날 수 있다.

5. 먼저 확인할 기본 점검 SQL

다음 SQL은 현재 서버의 관련 변수와 임시 테이블·정렬 지표를 빠르게 읽는 가장 기본적인 점검 예제다.

SELECT VERSION() AS mysql_version;

SHOW VARIABLES
WHERE Variable_name IN (
  'sort_buffer_size',
  'join_buffer_size',
  'tmp_table_size',
  'max_heap_table_size'
);

SHOW GLOBAL STATUS
WHERE Variable_name IN (
  'Created_tmp_tables',
  'Created_tmp_disk_tables',
  'Sort_merge_passes',
  'Sort_rows',
  'Sort_scan'
);

실행 결과(MySQL 8.0.46):

mysql> SELECT VERSION() AS mysql_version;

+---------------+
| mysql_version |
+---------------+
| 8.0.46        |
+---------------+
1 row in set (0.00 sec)

mysql> SHOW VARIABLES
    -> WHERE Variable_name IN (
    ->   'sort_buffer_size',
    ->   'join_buffer_size',
    ->   'tmp_table_size',
    ->   'max_heap_table_size'
    -> );

+---------------------+----------+
| Variable_name       | Value    |
+---------------------+----------+
| join_buffer_size    | 262144   |
| max_heap_table_size | 16777216 |
| sort_buffer_size    | 262144   |
| tmp_table_size      | 16777216 |
+---------------------+----------+
4 rows in set (0.00 sec)

mysql> SHOW GLOBAL STATUS
    -> WHERE Variable_name IN (
    ->   'Created_tmp_tables',
    ->   'Created_tmp_disk_tables',
    ->   'Sort_merge_passes',
    ->   'Sort_rows',
    ->   'Sort_scan'
    -> );

+-------------------------+-------+
| Variable_name           | Value |
+-------------------------+-------+
| Created_tmp_disk_tables | 0     |
| Created_tmp_tables      | 2     |
| Sort_merge_passes       | 0     |
| Sort_rows               | 0     |
| Sort_scan               | 0     |
+-------------------------+-------+
5 rows in set (0.00 sec)

6. 세션 단위로 유효 상한을 확인하면 무엇이 보이는가

다음 예제는 세션에서 tmp_table_sizemax_heap_table_size를 서로 다르게 설정한 뒤, 실제 메모리 임시 테이블이 기대할 수 있는 상한이 어느 값에 의해 제한되는지 확인하는 기본 재현 예제다.

핵심 목적은 “tmp_table_size 하나만 올리면 충분하다”는 오해를 버리는 데 있다. 실무에서는 두 값 중 작은 쪽이 실질적인 메모리 임시 테이블 상한으로 작동할 수 있으므로, 항상 쌍으로 읽어야 한다.

SET SESSION tmp_table_size = 33554432;
SET SESSION max_heap_table_size = 16777216;

SELECT
  @@session.tmp_table_size AS tmp_table_size_bytes,
  @@session.max_heap_table_size AS max_heap_table_size_bytes,
  LEAST(@@session.tmp_table_size, @@session.max_heap_table_size) AS effective_in_memory_tmp_upper_bound_bytes;

SHOW SESSION STATUS
WHERE Variable_name IN (
  'Created_tmp_tables',
  'Created_tmp_disk_tables'
);

실행 결과(MySQL 8.0.46):

mysql> SET SESSION tmp_table_size = 33554432;

Query OK, 0 rows affected (0.00 sec)

mysql> SET SESSION max_heap_table_size = 16777216;

Query OK, 0 rows affected (0.00 sec)

mysql> SELECT
    ->   @@session.tmp_table_size AS tmp_table_size_bytes,
    ->   @@session.max_heap_table_size AS max_heap_table_size_bytes,
    ->   LEAST(@@session.tmp_table_size, @@session.max_heap_table_size) AS effective_in_memory_tmp_upper_bound_bytes;

+----------------------+---------------------------+-------------------------------------------+
| tmp_table_size_bytes | max_heap_table_size_bytes | effective_in_memory_tmp_upper_bound_bytes |
+----------------------+---------------------------+-------------------------------------------+
|             33554432 |                  16777216 |                                  16777216 |
+----------------------+---------------------------+-------------------------------------------+
1 row in set (0.00 sec)

mysql> SHOW SESSION STATUS
    -> WHERE Variable_name IN (
    ->   'Created_tmp_tables',
    ->   'Created_tmp_disk_tables'
    -> );

+-------------------------+-------+
| Variable_name           | Value |
+-------------------------+-------+
| Created_tmp_disk_tables | 0     |
| Created_tmp_tables      | 0     |
+-------------------------+-------+
2 rows in set (0.00 sec)

이 예제에서 확인할 핵심은 다음과 같다.

  • tmp_table_size를 더 크게 설정해도 max_heap_table_size가 더 작으면 유효 상한은 그 값에 묶일 수 있다.
  • 실제 운영에서 디스크 임시 테이블 전환 여부는 row width, 집계 방식, 내부 TempTable 구현, 버전에 따라 달라질 수 있다.
  • 따라서 변수 숫자만 올린 뒤 지표를 보지 않으면, “올렸는데도 왜 디스크 임시 테이블이 줄지 않지?”라는 오해에 빠지기 쉽다.

7. 설정값만 보는 것보다 더 중요한 진단 질문

세션 메모리 변수는 숫자 자체보다 맥락이 중요하다. 다음 질문이 빠지면 튜닝이 아니라 추측이 된다.

7.1 왜 정렬이 이렇게 많이 발생하는가

  • 정렬이 필요한 SQL이 본질적으로 많은가
  • 복합 인덱스로 정렬을 피할 수 있는가
  • 먼저 필터링한 뒤 정렬하도록 쿼리를 바꿀 수 있는가
  • 애플리케이션이 필요 이상으로 큰 result set을 요청하는가

7.2 왜 join_buffer가 자주 필요한 실행 계획이 나오는가

  • 조인 키 인덱스가 빠져 있는가
  • 데이터 타입/콜레이션 불일치로 인덱스를 못 타는가
  • 함수 적용 때문에 SARGability가 깨졌는가
  • 파생 테이블/서브쿼리 구조 때문에 불필요하게 큰 join이 만들어지는가

7.3 왜 임시 테이블이 많고, 왜 디스크로 자주 내려가는가

  • GROUP BYDISTINCT를 더 작은 집합에서 수행할 수 있는가
  • Wide row를 임시 테이블에 넣고 있지는 않은가
  • 정렬과 집계가 한 번에 너무 큰 중간 결과를 만들고 있지는 않은가
  • 실제로는 메모리 부족보다 쿼리 설계 문제인 것은 아닌가

8. Aurora MySQL과 관리형 환경에서의 해석 차이

Aurora MySQL에서도 원칙은 같지만, 운영 해석에는 몇 가지 추가 층이 있다.

8.1 “버퍼를 키워 해결” 전략이 더 위험할 수 있다

Aurora는 스토리지 계층이 분리되어 있고 failover, reader/writer 역할, 파라미터 그룹 적용 범위가 일반 단일 인스턴스 MySQL과 다르다. 하지만 세션 메모리의 위험이 사라지는 것은 아니다. 오히려 다음 상황에서는 더 민감하다.

  • writer 인스턴스가 OLTP와 리포트 성격의 쿼리를 함께 받는 경우
  • 배치 시간대와 애플리케이션 피크가 겹치는 경우
  • failover 뒤 pool refill과 대형 쿼리가 같은 시간대에 몰리는 경우

이때 sort_buffer_size, join_buffer_size, tmp_table_size를 공격적으로 키워 두면, 평소에는 괜찮다가 재기동·failover·배치 폭주 시점에만 메모리 압박이 드러날 수 있다.

8.2 Parameter group 적용만 보고 끝내면 안 된다

Aurora/RDS에서는 변수 변경 가능 여부와 실제 운영 효과를 분리해서 봐야 한다.

  • dynamic 변수인지
  • cluster parameter group인지 instance parameter group인지
  • writer와 reader에 같은 값이 필요한지
  • 애플리케이션이 특정 reader에서만 대형 정렬을 수행하는지

예를 들어 reader에서만 큰 분석 쿼리가 돈다면, 모든 인스턴스에 같은 세션 메모리 전략을 강제하는 것이 최선이 아닐 수 있다.

8.3 Performance Insights/CloudWatch와 함께 읽어야 한다

Aurora에서는 단순 변수값보다도, 특정 시간대의 DB load, temp usage 패턴, 정렬/임시 테이블 관련 SQL 상위 항목을 함께 읽어야 한다. 즉, 세션 메모리 변수는 독립적인 숫자가 아니라 워크로드 모양에 대한 반응값으로 다뤄야 한다.

9. 흔한 오해와 실패 패턴

9.1 “디스크 임시 테이블이 보이니 무조건 나쁘다”는 오해

온디스크 임시 테이블은 비용이 들 수 있지만, 메모리 상한을 지키기 위한 안전장치이기도 하다. 운영자는 Created_tmp_disk_tables 숫자를 없애는 것보다, 과도하게 자주 발생하는지, 문제가 되는 SQL이 무엇인지, 메모리로 억지로 올렸을 때 더 큰 위험이 생기지 않는지를 함께 봐야 한다.

9.2 “join_buffer를 키우면 join이 빨라진다”는 오해

이 말은 조건부로만 맞다. 인덱스 없는 join이 문제인 경우, 버퍼 증설은 임시 완화에 불과하다. 장기적으로는 잘못된 실행 계획을 유지시키는 방향으로 작동할 수 있다.

9.3 “sort_buffer를 키우면 정렬 문제는 해결된다”는 오해

많은 정렬 문제는 버퍼 부족보다 정렬해야 할 행 수가 너무 큰 데서 시작한다. 정렬 전에 집합을 줄이거나 인덱스로 정렬 자체를 피하는 설계가 훨씬 큰 효과를 낼 수 있다.

9.4 “메모리 남는 서버니까 세션 버퍼도 크게 잡아도 된다”는 오해

남는 메모리는 평균 상태를 말할 뿐이다. 세션 버퍼 위험은 동시성 피크와 나쁜 쿼리 폭주에서 나타난다. 특히 컨테이너 메모리 제한, cgroup 제한, 기타 공존 프로세스가 있는 환경에서는 더 조심해야 한다.

10. 운영 체크리스트

  • sort_buffer_size
  • join_buffer_size를 만지기 전에 EXPLAIN
  • tmp_table_sizemax_heap_table_size
  • Created_tmp_disk_tables, Created_tmp_tables, Sort_rows, Sort_merge_passes

11. 권장 판단 기준

실무적으로는 다음 순서를 권장한다.

  1. 먼저 SQL과 인덱스 구조를 본다.
  2. 다음으로 정렬·조인·임시 테이블이 왜 필요한지 실행 계획을 본다.
  3. 그 다음에만 세션 메모리 변수를 소폭 조정한다.
  4. 조정 후에는 단일 쿼리 체감이 아니라 피크 시간대 메모리와 동시성 영향을 확인한다.

즉, 이 세 변수는 1차 해결책이 아니라 3차 미세 조정 도구에 가깝다. 운영 서버에서 가장 위험한 패턴은 원인 분석 없이 숫자부터 키우는 것이다.

12. 결론

sort_buffer_size, join_buffer_size, tmp_table_size는 이름만 보면 정렬·조인·임시 테이블을 더 잘 처리하게 만드는 성능 옵션처럼 보인다. 그러나 운영 관점에서 이 세 변수는 세션별 작업 메모리의 상한을 늘리는 손잡이다. 이 손잡이를 크게 돌릴수록 단일 쿼리의 체감 개선보다, 동시성 피크 시점의 메모리 압박과 장애 반경이 더 커질 수 있다.

따라서 안전한 접근은 항상 같다.

  • 정렬이 왜 필요한지 본다.
  • 조인이 왜 인덱스를 못 타는지 본다.
  • 임시 테이블이 왜 커지는지 본다.
  • 그 뒤에만 버퍼 값을 조정한다.

다음 글에서는 이러한 세션 작업 메모리 논의와 직접 연결되는 주제로, MySQL의 내부 임시 테이블이 어떤 조건에서 메모리에서 디스크로 전환되는지와 Created_tmp_disk_tables 지표를 어떻게 읽어야 하는지를 더 깊게 다룰 수 있다.