---
title: "MySQL 8.0.22 릴리스 노트"
description: "MySQL 8.0.22 Community Server 릴리스 노트를 한국어로 번역하고, DBA가 참고해야 할 핵심 내용을 함께 정리하였습니다."
tags: [ MySQL, 릴리스노트 ]
image: "mysql-release-note.png"
author: "Oracle"
published: "2020-10-19"
updated: ""
source_url: "https://dev.mysql.com/doc/relnotes/mysql/8.0/en/news-8-0-22.html"
---

## DBA를 위한 핵심 내용

MySQL 8.0.22는 prepared statement 준비 시점 변경, 복제 용어 변경, Performance Schema 관측성 강화가 핵심입니다. 성능 개선 효과가 있지만 SQL 의미와 타입 결정 방식이 바뀌어 애플리케이션 호환성 리스크가 크며, 외부에서도 prepared statement 비호환 사례가 보고되었습니다. ([Zenn](https://zenn.dev/tmtms/articles/202011-mysql-8022-prepared-statement?locale=en))

1. prepared statement와 저장 프로시저 내부 문장이 매 실행마다가 아니라 준비 시점에 한 번 준비되도록 변경되었습니다. 파라미터·사용자 변수 타입이 고정되므로 `ORDER BY ?`, `LIMIT ?`, 윈도우 함수 인자, JSON/문자열 캐스팅을 쓰는 애플리케이션은 결과·오류·실행 계획 차이를 반드시 검증해야 합니다.
2. `START/STOP/SHOW/RESET SLAVE` 계열이 사용 중단되고 `REPLICA` 용어 별칭이 도입되었습니다. 명령은 계속 동작하지만 운영 표준, runbook, 모니터링 상태 변수명을 새 명칭으로 전환하는 것이 좋습니다.
3. `SHOW PROCESSLIST`의 Performance Schema 기반 대체 구현과 `performance_schema.error_log` 테이블이 추가되었습니다. 고동시성 환경에서는 processlist mutex 영향을 줄일 수 있으나, 동일 정보 노출을 위해 Performance Schema 설정 요구사항을 확인해야 합니다.
4. `ALTER DATABASE ... READ ONLY`가 추가되어 마이그레이션 중 스키마 변경 방지에 활용할 수 있습니다. 단순 `read_only` 서버 옵션과 범위가 다르므로 데이터베이스 단위 이전 절차에 반영할 가치가 있습니다.
5. 비동기 복제 연결 자동 페일오버가 도입되었습니다. `SOURCE_CONNECTION_AUTO_FAILOVER`와 소스 목록 관리 함수로 I/O 스레드 장애 대응을 자동화할 수 있지만, 승격 정책·데이터 정합성·애플리케이션 라우팅과 함께 설계해야 합니다.
6. InnoDB의 `innodb_extend_and_initialize`, redo log writer 튜닝, grant table lock-free read, 다수의 instant DDL/clone/Group Replication 수정이 포함되었습니다. 업그레이드 후 DDL, 통계 생성, Group Replication 재참여, LDAP/client-plugin 패키징을 운영 환경 기준으로 점검하십시오.

## 계정 관리 관련 사항

- grant 테이블과 관련된 구문의 잠금 처리가 개선되었습니다. (Bug #31291237, Bug #31576185, WL #14084)
- `mysql.infoschema` 및 `mysql.sys` 예약 계정을 수정하려면 이제 [`SYSTEM_USER`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/privileges-provided.html#priv_system-user) 권한이 필요합니다. (Bug #31255458)
- [`CREATE USER`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/create-user.html), [`DROP USER`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/drop-user.html), [`RENAME USER`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/rename-user.html) 계정 관리 구문의 경우, 서버는 이제 저장된 객체가 고아 상태가 되게 하거나 (아마도 의도치 않게) 현재 고아 상태인 저장된 객체가 채택되게 하는 작업을 방지하도록 설계된 추가 보안 검사를 수행합니다. 이러한 작업은 이제 오류와 함께 실패합니다. [`SET_USER_ID`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/privileges-provided.html#priv_set-user-id) 권한이 있으면 해당 권한이 검사를 재정의하며 이러한 작업은 오류가 아니라 경고를 발생시킵니다. 이를 통해 관리자는 해당 작업이 의도적으로 필요한 경우 작업을 수행할 수 있습니다. [Orphan Stored Objects](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/stored-objects-security.html#stored-objects-security-orphan-objects)를 참조하십시오. (WL #14073)

## Audit Log 관련 사항

- JSON 형식 로그 파일의 경우, MySQL Enterprise Audit는 [`audit_log_read()`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/audit-log-reference.html#function_audit-log-read) 사용자 정의 함수를 사용한 로그 읽기 작업을 지원합니다. 이전에는 읽기를 시작할 위치를 지정하려면 특정 이벤트의 정확한 타임스탬프와 이벤트 ID를 나타내는 북마크가 포함된 인수를 [`audit_log_read()`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/audit-log-reference.html#function_audit-log-read)에 전달하는 방법만 가능했습니다. 더 높은 유연성을 위해, 이제 인수는 임의의 타임스탬프를 지정하는 시작 지정자가 될 수 있으며, 해당 타임스탬프 또는 그 이후에 발생하는 첫 번째 이벤트부터 읽습니다. [Audit Log 파일 읽기](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/audit-log-file-reading.html)를 참조하십시오. (WL #13936)

## C API 관련 사항

- MySQL 클라이언트 라이브러리에는 이제 [`mysql_real_connect_dns_srv()`](https://docs.oracle.com/cd/E17952_01/c-api-8.0-en/mysql-real-connect-dns-srv.html) C API 함수가 포함됩니다. 이 함수는 [`mysql_real_connect()`](https://docs.oracle.com/cd/E17952_01/c-api-8.0-en/mysql-real-connect.html)와 유사하지만, 명시적인 호스트, 포트, 소켓 인자 대신 DNS SRV 레코드를 사용하여 MySQL 서버에 대한 연결을 설정하기 위한 후보 호스트를 결정합니다.

  C API를 사용하는 애플리케이션은 새 함수를 직접 호출할 수 있습니다. 또한 **mysql** 클라이언트 프로그램은 DNS SRV 기능을 사용하도록 수정되었습니다. 이제 [`--dns-srv-name`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/mysql-command-options.html#option_mysql_dns-srv-name) 옵션을 지원하며, 이 옵션은 [`--host`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/mysql-command-options.html#option_mysql_host)보다 우선하고 DNS SRV 레코드를 기반으로 연결이 수행되도록 합니다. [mysql_real_connect_dns_srv()](https://docs.oracle.com/cd/E17952_01/c-api-8.0-en/mysql-real-connect-dns-srv.html)를 참조하십시오.

  다른 컨텍스트에서의 연결 설정은 영향을 받지 않으며, 여기에는 복제본, `FEDERATED` 스토리지 엔진, **mysql** 이외의 클라이언트 프로그램이 수행하는 연결이 포함됩니다. (WL #13905)

## 컴파일 관련 사항

- Windows에서 Visual Studio 2019 Update 4가 이제 MySQL 컴파일을 위한 최소 버전입니다. (Bug #31655401)
- 서버 빌드를 위한 Boost 라이브러리의 최소 버전은 이제 1.73.0입니다. (Bug #31309800)

## 설정 관련 사항

- 새로운 [`WITH_TCMALLOC`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/source-configuration-options.html#option_cmake_with_tcmalloc) **CMake** 옵션은 `-ltcmalloc`과 링크할지 여부를 나타냅니다. 활성화하면 내장 `malloc()`, `calloc()`, `realloc()`, `free()` 루틴이 비활성화됩니다. 기본값은 `OFF`입니다. [`WITH_TCMALLOC`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/source-configuration-options.html#option_cmake_with_tcmalloc)과 [`WITH_JEMALLOC`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/source-configuration-options.html#option_cmake_with_jemalloc)은 상호 배타적입니다. (Bug #31785166)
- 새로운 [`COMPRESS_DEBUG_SECTIONS`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/source-configuration-options.html#option_cmake_compress_debug_sections) **CMake** 옵션은 바이너리 실행 파일의 디버그 섹션을 압축할지 여부를 나타냅니다(Linux 전용). 실행 파일 디버그 섹션을 압축하면 빌드 프로세스 중 추가 CPU 시간을 사용하는 대신 공간을 절약합니다. 기본값은 `OFF`입니다. 이 옵션이 명시적으로 설정되지 않았지만 `COMPRESS_DEBUG_SECTIONS` 환경 변수가 설정되어 있으면, 옵션은 해당 변수에서 값을 가져옵니다. (Bug #31498296)
- [`WITH_DEFAULT_FEATURE_SET`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/source-configuration-options.html#option_cmake_with_default_feature_set) **CMake** 옵션이 제거되었습니다. (Bug #31122507)
- 네트워크 네임스페이스 지원을 구현하는 플랫폼(예: Linux)에서 MySQL은 이제 클라이언트 프로그램에서 MySQL 서버 또는 X Plugin으로의 TCP/IP 연결에 대해 네트워크 네임스페이스 설정을 활성화합니다:

  - 서버 측에서는 [`bind_address`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/server-system-variables.html#sysvar_bind_address), [`admin_address`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/server-system-variables.html#sysvar_admin_address), [`mysqlx_bind_address`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/x-plugin-options-system-variables.html#sysvar_mysqlx_bind_address) 시스템 변수가 수신 연결을 대기할 지정된 IP 주소 또는 호스트 이름에 사용할 네트워크 네임스페이스를 지정하기 위한 확장 문법을 갖습니다.
  - 클라이언트 연결의 경우, **mysql** 클라이언트와 **mysqlxtest** 테스트 스위트 클라이언트는 네트워크 네임스페이스를 지정하기 위한 [`--network-namespace`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/mysql-command-options.html#option_mysql_network-namespace) 옵션을 지원합니다.
  - 복제 서버에서 소스 서버로의 복제 연결의 경우, [`CHANGE MASTER TO`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/change-master-to.html) 문은 네트워크 네임스페이스를 지정하기 위한 `NETWORK_NAMESPACE` 옵션을 지원합니다.

    복제 모니터링 목적을 위해 Performance Schema `replication_connection_configuration` 테이블, 레플리카 서버 연결 메타데이터 저장소([Replication Metadata Repositories](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/replica-logs-status.html) 참조), 그리고 [`SHOW REPLICA | SLAVE STATUS`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/show-replica-status.html) 구문에는 연결에 적용 가능한 네트워크 네임스페이스를 표시하는 새 컬럼이 있습니다.

  이 기능을 사용하기 위해 충족해야 하는 호스트 시스템 전제 조건을 포함한 자세한 내용은 [Network Namespace Support](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/network-namespace-support.html)를 참조하십시오. (WL #12720)

## 사용 중단 및 제거 관련 사항

- MySQL 8.0.22부터 `group_replication_ip_whitelist` 시스템 변수는 사용 중단되었으며, 이를 대체하기 위해 시스템 변수 `group_replication_ip_allowlist`가 추가되었습니다. 이 시스템 변수는 이전과 동일한 방식으로 동작하며, 용어만 변경되었습니다.

  두 시스템 변수 모두 기본값은 `AUTOMATIC`입니다. 시스템 변수 중 하나가 사용자 정의 값으로 설정되어 있고 다른 하나는 설정되지 않은 경우, 변경된 값이 사용됩니다. 두 시스템 변수가 모두 사용자 정의 값으로 설정된 경우, `group_replication_ip_allowlist`의 값이 사용됩니다. (WL #14175)
- MySQL 8.0.22부터 `START SLAVE`, `STOP SLAVE`, `SHOW SLAVE STATUS`, `SHOW SLAVE HOSTS`, `RESET SLAVE` 문은 사용 중단되었습니다. 대신 다음 별칭을 사용해야 합니다:

  - `START SLAVE` 대신 `START REPLICA`를 사용하십시오.
  - `STOP SLAVE` 대신 `STOP REPLICA`를 사용하십시오.
  - `SHOW SLAVE STATUS` 대신 `SHOW REPLICA STATUS`를 사용하십시오.
  - `SHOW SLAVE HOSTS` 대신 `SHOW REPLICAS`를 사용하십시오.
  - `RESET SLAVE` 대신 `RESET REPLICA`를 사용하십시오.

  이 문은 이전과 동일한 방식으로 동작하며, 각 문과 그 출력에 사용되는 용어만 변경되었습니다.

  관련 상태 변수의 별칭으로 새 상태 변수가 추가되었습니다. 이 문의 이전 버전과 새 버전은 모두 이러한 상태 변수의 이전 버전과 새 버전을 모두 업데이트합니다:

  - `Com_slave_start`는 `Com_replica_start`와 동일합니다.
  - `Com_slave_stop`는 `Com_replica_stop`와 동일합니다.
  - `Com_show_slave_status`는 `Com_show_replica_status`와 동일합니다.
  - `Com_show_slave_hosts`는 `Com_show_replicas`와 동일합니다.

  (WL #14171)

- InnoDB memcached 플러그인은 사용 중단되었으며 이에 대한 지원은 향후 MySQL 버전에서 제거될 예정입니다. (WL #14131)
- [`INFORMATION_SCHEMA.TABLESPACES`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/information-schema-tablespaces-table.html) 테이블은 사용되지 않습니다. 이제 이 테이블은 사용 중단되었으며 향후 MySQL 버전에서 제거될 예정입니다. [The INFORMATION_SCHEMA TABLESPACES Table](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/information-schema-tablespaces-table.html)에 설명된 것처럼 다른 `INFORMATION_SCHEMA` 테이블에서 관련 정보를 제공할 수 있습니다. (WL #14064)

## Keyring 관련 사항

- MySQL Enterprise Edition에는 이제 keyring 스토리지의 백엔드로 Oracle Cloud Infrastructure Vault를 사용하는 `keyring_oci` 플러그인이 포함됩니다. 키 정보는 MySQL 서버 로컬 스토리지에 영구적으로 저장되지 않습니다. 모든 키는 Oracle Cloud Infrastructure Vault에 저장되므로, 이 플러그인은 Oracle Cloud Infrastructure MySQL 고객이 MySQL Enterprise Edition 키를 관리하는 데 적합합니다. 자세한 내용은 [The MySQL Keyring](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/keyring.html)을 참조하십시오. (WL #9770)

## Optimizer 관련 사항

- **중요한 변경:** 이제 준비된 명령문은 실행될 때마다 한 번씩이 아니라, [`PREPARE`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/prepare.html)를 실행할 때 한 번만 준비됩니다. 또한 저장 프로시저 내부의 명령문도 이제 저장 프로시저가 처음 실행될 때 한 번만 준비됩니다. 이 변경은 반복적인 준비와 준비 구조의 롤백에 따른 추가 비용을 피하므로 이러한 명령문의 성능을 향상하며, 후자는 여러 버그의 원인이었습니다.

  이 작업의 일부로, 준비된 명령문에서 사용되는 동적 매개변수가 해석되는 방식이 변경되었으며, 이에 따른 준비된 명령문 사용 사례의 변경 사항은 다음과 같습니다:

  - 준비된 명령문에서 사용되는 매개변수는 명령문이 준비될 때 데이터 타입이 결정되며, 명령문이 다시 준비되지 않는 한 해당 타입은 명령문의 이후 각 실행에 대해 유지됩니다(이러한 일이 발생할 수 있는 경우에 대한 정보는 [PREPARE Statement](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/prepare.html)를 참조하십시오).
  - `SELECT expr1, expr2,... FROM table ORDER BY ?` 형식의 준비된 명령문에서 매개변수에 정수 값 *`N`*을 전달해도 더 이상 select 목록의 *`N`*번째 표현식으로 결과가 정렬되지 않으며, `ORDER BY constant`에서 예상되는 것처럼 결과는 더 이상 정렬되지 않습니다.
  - 매개변수(및 경우에 따라 사용자 변수)를 통해 부동소수점 값을 `LIMIT` 또는 `OFFSET` 절에 삽입하는 것이 가능했습니다(지원되지는 않았지만). 이제 이는 명시적으로 허용되지 않으며, 이러한 값은 정수여야 합니다.
  - SQL 표준을 준수하기 위해, *`nn`*이 음수인 윈도우 함수 [`NTILE(NULL)`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/window-function-descriptions.html#function_ntile), [`NTH_VALUE(expr, NULL)`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/window-function-descriptions.html#function_nth-value), [`LEAD(expr, nn)`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/window-function-descriptions.html#function_lead), [`LAG(expr, nn)`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/window-function-descriptions.html#function_lag)는 이제 허용되지 않습니다.
  - 준비된 명령문에서 읽는 사용자 변수는 이제 명령문이 준비될 때 타입이 결정되며, 해당 타입은 명령문의 이후 각 실행에 대해 유지됩니다.
  - 저장 프로시저 내의 명령문에서 읽는 사용자 변수는 이제 해당 명령문이 처음 실행될 때 타입이 결정되며, 해당 타입은 이를 포함하는 저장 프로시저의 이후 모든 호출에 대해 유지됩니다.
  - 매개변수 타입을 결정할 수 있는 문맥 정보가 없는 매개변수의 경우, 서버는 해당 매개변수가 바이너리 문자열이 아니라 기본 캐릭터셋을 사용하는 문자 문자열이라고 가정합니다. 이 가정이 올바르지 않은 매개변수는 [`CAST()`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/cast-functions.html#function_cast) 표현식 안에 배치할 수 있습니다.

    [PREPARE Statement](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/prepare.html)를 참조하여, prepared statement 내에서 사용되는 파라미터와 사용자 변수의 유효 데이터 타입이 결정되는 방식을 지배하는 규칙을 확인하십시오.

  또한 윈도우 함수 [`LAG()`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/window-function-descriptions.html#function_lag), [`LEAD()`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/window-function-descriptions.html#function_lead), [`NTILE()`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/window-function-descriptions.html#function_ntile)에 대한 rows (*`N`*) 인수는 이제 다음 형식 중 하나로, `0`부터 `263`까지의 범위(양 끝 포함)에 있는 정수여야 합니다:

  - unsigned integer constant literal
  - positional parameter marker (`?`)
  - 사용자 정의 변수
  - stored routine의 로컬 변수

  또한 이 인수는 더 이상 `NULL`이 될 수 없습니다. 자세한 내용은 방금 참조한 함수 설명을 참조하십시오. (Bug #48612, Bug #99601, Bug #100150, Bug #105166, Bug #11756670, Bug #23599127, Bug #31119132, Bug #31365678, Bug #31393719, Bug #31592822, Bug #31810577, Bug #33448735, WL #9384)
- `filesort` 알고리즘은 이제 단일 테이블뿐만 아니라 여러 테이블에 대한 join 정렬도 지원합니다. (Bug #31310238, Bug #31559978, Bug #31563876)
- `RIGHT JOIN`을 사용할 때 일부 내부 객체가 의도한 대로 `LEFT JOIN`에 사용하기에 적합한 객체로 변환되지 않았습니다. 여기에는 parse 시점에 생성되었지만 순서가 반대로 바뀌지 않은 일부 테이블 목록이 포함되었습니다. 이로 인해 `LEFT JOIN`이 원래 `RIGHT JOIN`이었던 인스턴스를 특수 사례로 처리하기 위한 코드를 유지해야 했으며, 이는 여러 버그의 원인이었습니다. 이제 서버는 parse 시점에 필요한 모든 순서 반전을 수행하므로, parse 이후에는 `RIGHT JOIN`이 실제로 모든 면에서 `LEFT JOIN`입니다. (Bug #30887665, Bug #30964002, WL #6509)

  참조: 함께 참조하십시오: Bug #12567331, Bug #21350125.

- [`SELECT INTO DUMPFILE`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/select-into.html) 및 `SELECT INTO OUTFILE` 문으로 파일에 쓸 때 주기적인 동기화에 대한 지원이 추가되었습니다. 이 기능은 [`select_into_disk_sync`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/server-system-variables.html#sysvar_select_into_disk_sync) 시스템 변수를 `ON`으로 설정하여 활성화할 수 있습니다. 쓰기 버퍼의 크기는 서버 시스템 변수 [`select_into_buffer_size`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/server-system-variables.html#sysvar_select_into_buffer_size)를 사용하여 설정할 수 있습니다. 기본 버퍼 크기는 131072(217)바이트입니다. 디스크 동기화 후의 선택적 지연도 [`select_into_disk_sync_delay`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/server-system-variables.html#sysvar_select_into_disk_sync_delay) 시스템 변수를 사용하여 설정할 수 있습니다. 기본 동작은 어떠한 지연도 허용하지 않는 것입니다(즉, 지연 시간 0밀리초).

  자세한 내용은 앞서 참조된 시스템 변수 설명을 참조하십시오.

  MySQL 8.0에 대한 이 기여에 대해 Facebook에 감사드립니다. (Bug #30284861, WL #13926)
- MySQL은 이제 적합한 쿼리에 대해 파생 조건 푸시다운을 구현합니다. 이것이 의미하는 바는 `SELECT * FROM (SELECT i, j FROM t1) AS dt WHERE i > constant`와 같은 쿼리의 경우, 이제 많은 경우 외부 `WHERE` 조건을 파생 테이블로 푸시다운할 수 있으며, 이 경우 결과는 `SELECT * FROM (SELECT i, j FROM t1 WHERE i > constant) AS dt`가 됩니다. 이전에는 파생 테이블이 구체화되고 병합되지 않은 경우 MySQL은 전체 테이블(이 경우 `t1`)을 구체화한 다음 `WHERE` 조건으로 로우를 판별했습니다.

  파생 테이블을 외부 쿼리로 병합할 수 없는 경우(예를 들어 파생 테이블이 집계를 사용하는 경우), 외부 `WHERE` 조건을 파생 테이블로 푸시다운하면 처리해야 하는 로우 수를 줄일 수 있으며, 이는 쿼리 성능을 향상시킬 수 있습니다.

  파생 테이블이 집계 함수나 윈도우 함수를 사용하지 않는 경우 외부 `WHERE` 조건을 구체화된 파생 테이블로 직접 푸시다운할 수 있습니다. 또한 파생 테이블에 `GROUP BY`가 있고 윈도우 함수를 사용하지 않는 경우, 외부 `WHERE` 조건을 파생 테이블에 `HAVING` 조건으로 푸시다운할 수 있습니다. 파생 테이블이 윈도우 함수를 사용하고 외부 `WHERE`가 윈도우 함수의 `PARTITION` 절에서 사용되는 컬럼을 참조하는 경우에도, `WHERE` 조건을 푸시다운할 수 있습니다.

  이 최적화는 [`UNION`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/union.html) 또는 `LIMIT` 절을 포함하는 파생 테이블에는 사용할 수 없습니다.

  파생 조건 푸시다운을 활성화하려면 [`optimizer_switch`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/server-system-variables.html#sysvar_optimizer_switch) 시스템 변수의 [`derived_condition_pushdown`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/switchable-optimizations.html#optflag_derived-condition-pushdown) 플래그(이번 릴리스에서 추가됨)를 `on`으로 설정해야 합니다. 이것이 기본 설정입니다. 이 최적화가 Optimizer switch 설정에 의해 비활성화된 경우, [`DERIVED_CONDITION_PUSHDOWN`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/optimizer-hints.html#optimizer-hints-table-level) Optimizer 힌트(역시 이번 릴리스에서 추가됨)를 사용하여 특정 쿼리에 대해 이를 활성화할 수 있습니다. 지정된 쿼리에 대해 이 최적화를 비활성화하려면 [`NO_DERIVED_CONDITION_PUSHDOWN`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/optimizer-hints.html#optimizer-hints-table-level) Optimizer 힌트를 사용하십시오.

  자세한 정보와 예시는 [Derived Condition Pushdown Optimization](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/derived-condition-pushdown-optimization.html)을 참조하십시오. (Bug #59870, Bug #88381, Bug #11766303, Bug #27590273, WL #8084)

## 패키징 관련 사항

- RPM 및 Debian 패키지의 경우, 클라이언트 측 플러그인이 자체 client-plugins 패키지로 이동되었습니다. (Bug #31584093)
- MySQL 소스 배포판의 `VERSION` 파일은 Boost와의 이름 충돌로 인해 이제 `MYSQL_VERSION`으로 명명됩니다. (Bug #31466846)
- MySQL이 `WITH_SYSTEMD=1`로 빌드되는 플랫폼의 경우, 패키지는 더 이상 레거시 System V 파일을 포함하지 않습니다: **mysqld_multi.server** 및 **mysql.server** 스크립트와 `mysql.server.1`, `mysqld_multi.1`, `mysqld_safe.1` man 페이지입니다. (Bug #31450888)

## Performance Schema 관련 사항

- [`SHOW PROCESSLIST`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/show-processlist.html) 문은 모든 활성 스레드에서 스레드 데이터를 수집하여 프로세스 정보를 제공합니다. 그러나 구현이 전역 mutex를 보유한 상태로 스레드 관리자 내부에서 활성 스레드를 순회하므로, 특히 사용량이 많은 시스템에서 성능에 부정적인 결과를 초래합니다.

  이제 새로운 Performance Schema [`processlist`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/performance-schema-processlist-table.html) 테이블을 기반으로 하는 대체 [`SHOW PROCESSLIST`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/show-processlist.html) 구현을 사용할 수 있습니다. 이 구현은 스레드 관리자 대신 Performance Schema에서 활성 스레드 데이터를 쿼리하며 mutex가 필요하지 않습니다:

  - 대체 구현을 활성화하려면 [`performance_schema_show_processlist`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/performance-schema-system-variables.html#sysvar_performance_schema_show_processlist) 시스템 변수를 활성화하십시오.
  - [`SHOW PROCESSLIST`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/show-processlist.html)의 대체 구현은 **mysqladmin processlist** 명령에도 적용됩니다.
  - 대체 구현은 `INFORMATION_SCHEMA` [`PROCESSLIST`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/information-schema-processlist-table.html) 테이블이나 MySQL 클라이언트/서버 프로토콜의 `COM_PROCESS_INFO` 명령에는 적용되지 않습니다.
  - 기본 구현과 대체 구현이 동일한 정보를 산출하도록 하려면 특정 설정 요구 사항을 충족해야 합니다. [The processlist Table](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/performance-schema-processlist-table.html)을 참조하십시오.

  (WL #9090)

- MySQL 서버 오류 로그에 기록된 가장 최근 이벤트에 대한 SQL 인터페이스를 이제 새로운 Performance Schema [`error_log`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/performance-schema-error-log-table.html) 테이블에 대한 쿼리를 통해 사용할 수 있습니다. 이 테이블은 고정 크기를 가지며, 새 이벤트를 위한 공간을 확보하기 위해 필요에 따라 오래된 이벤트가 자동으로 폐기됩니다. 오류 로그 설정에 이 기능을 지원하는 로그 싱크 컴포넌트(현재 traditional-format `log_sink_internal` 및 JSON-format `log_sink_json` 싱크)가 포함된 경우 테이블이 채워집니다. 여러 새 상태 변수가 [`error_log`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/performance-schema-error-log-table.html) 테이블 동작에 대한 정보를 제공합니다. [The error_log Table](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/performance-schema-error-log-table.html)을 참조하십시오. (WL #13681)

## Pluggable Authentication 관련 사항

- LDAP 인증 플러그인에 다음 변경 사항이 적용되었습니다:

  - SASL LDAP 인증 플러그인의 경우, `SCRAM-SHA-1` 인증 메서드는 SLES 12 및 15와 EL6 시스템에서 지원되지 않습니다. 해당 시스템의 기본 메서드는 이제 `GSSAPI`입니다.
  - LDAP 호스트가 설정되지 않은 경우 LDAP 연결 풀이 초기화되지 않으며, 이로 인해 이전에는 실패했을 경우에도 인증 플러그인 설치가 성공할 수 있습니다. (사이트에서 먼저 플러그인을 설치한 다음 나중에 설정하는 경우가 이에 해당할 수 있습니다.)
  - LDAP 연결 매개변수가 런타임에 변경되면, LDAP 연결 풀은 이후 첫 번째 인증 시도에서 다시 초기화됩니다.
  - LDAP 서버가 재시작되면 연결 풀의 기존 연결은 유효하지 않게 됩니다. LDAP 인증 플러그인은 이 경우를 감지하고 연결 풀을 다시 초기화하며, (SASL LDAP 플러그인의 경우) SASL challenge가 다시 전송됩니다.

  (Bug #31664270, Bug #31219323)

## SQL 문법 관련 사항

- 파서는 이제 다음 문법을 사용하여 괄호로 둘러싼 쿼리 표현식을 지원합니다:

  ```
  ( query_expression )
    [order_by_clause]
    [limit_clause]
    [into_clause]
  ```

  다른 변형도 가능합니다. [Parenthesized Query Expressions](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/parenthesized-query-expressions.html)를 참조하십시오. (Bug #30592703)
- 이제 [`CAST()`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/cast-functions.html#function_cast) 함수 또는 [`CONVERT()`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/cast-functions.html#function_convert) 함수를 사용하여 다른 타입의 값을 [`YEAR`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/year.html)로 캐스트할 수 있습니다. 이제 이러한 함수는 0-99 범위의 한 자리 또는 두 자리 `YEAR` 값과 1901-2155 범위의 네 자리 값을 지원합니다. 정수 0은 Year 0으로 변환됩니다. 하나 이상의 0으로 구성된 문자열은 가능한 잘림 이후에 2000년으로 변환됩니다. 캐스트는 1-69 범위의 값에 2000을 더하고, 70-99 범위의 값에 1900을 더합니다.

  하나, 둘 또는 네 개의 숫자로 시작하고 뒤이어 하나 이상의 숫자가 아닌 문자(그리고 다른 숫자 또는 숫자가 아닌 문자가 있을 수 있음)가 오는 문자열은 `YEAR`로 변환되기 전에 잘립니다. 이러한 경우 서버는 잘림 경고를 발생시킵니다. 부동소수점 값은 변환 전에 반올림됩니다. `CAST(1944.5 AS YEAR)`는 반올림으로 인해 1945를 반환하고, `CAST("1944.5" AS YEAR)`는 잘림으로 인해 1944를 반환합니다(경고 포함).

  [`DATE`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/datetime.html), [`DATETIME`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/datetime.html), [`TIMESTAMP`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/datetime.html)는 값의 `YEAR` 부분으로 캐스트됩니다. [`TIME`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/time.html) 값은 현재 연도로 캐스트됩니다. 캐스트할 값을 `TIME` 값으로 지정하지 않으면 예상과 다른 결과가 나올 수 있습니다. `CAST("13:47" AS YEAR)`는 문자열 값의 잘림으로 인해 2013을 반환하고, `CAST(TIME "13:47" AS YEAR)`는 이 릴리스의 연도 기준으로 2020을 반환합니다.

  [`GEOMETRY`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/spatial-type-overview.html) 값을 `YEAR`로 캐스트하는 것은 지원되지 않습니다. 호환되지 않는 타입, 범위를 벗어난 값 또는 잘못된 값을 캐스트하면 `NULL`을 반환합니다.

  `YEAR`는 [`JSON_VALUE()`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/json-search-functions.html#function_json-value) 함수의 반환 타입으로도 사용할 수 있습니다. 이 함수는 네 자리 연도만 지원하며, 그 외에는 `YEAR`로 캐스트를 수행할 때 `CAST()` 및 `CONVERT()`에 적용되는 것과 동일한 규칙을 따릅니다.

  자세한 내용은 [`CONVERT()`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/cast-functions.html#function_convert) 함수 설명을 참조하십시오. (WL #14015)
- [`TIMESTAMP`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/datetime.html) 컬럼 값을 선택할 때, 이번 릴리스에서 `CAST()` 함수에 대해 구현된 `AT TIME ZONE` 연산자를 사용하여 값을 가져오는 시점에 시스템 시간대에서 UTC [`DATETIME`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/datetime.html)으로 변환할 수 있게 되었습니다.

  문법은 `CAST(value AT TIME ZONE specifier AS DATETIME[(precision)])`이며, 여기서 *`value`*는 `TIMESTAMP`이고, *`specifier`*는 `[INTERVAL] '+00:00'` 또는 `'UTC'` 중 하나입니다. (`INTERVAL`은 지정자의 첫 번째 형식에서 선택 사항이며, `'UTC'`와 함께 사용할 수 없습니다.) 캐스트가 반환하는 `DATETIME` 값의 *`precision`*은 선택적으로 소수점 이하 6자리까지 지정할 수 있습니다.

  시간대 오프셋을 사용하여 테이블에 삽입된 값도 지원됩니다.

  `AT TIME ZONE`은 [`CONVERT()`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/cast-functions.html#function_convert)와 함께 사용할 수 없으며, `CAST()` 함수 호출의 일부인 경우 이외의 다른 컨텍스트에서도 사용할 수 없습니다. `AT TIME ZONE`을 사용할 때는 `ARRAY` 키워드와 다중 값 인덱스 생성도 지원되지 않습니다.

  간단한 예는 다음과 같습니다:

  ```
  mysql> SELECT @@system_time_zone;
  +--------------------+
  | @@system_time_zone |
  +--------------------+
  | EDT                |
  +--------------------+
  1 row in set (0.00 sec)

  mysql> CREATE TABLE ex (ts TIMESTAMP);
  Query OK, 0 rows affected (0.81 sec)

  mysql> INSERT INTO ex VALUES
       >     ROW(CURRENT_TIMESTAMP),
       >     ROW('2020-07-31 21:44:30-08:00');
  Query OK, 2 rows affected (0.09 sec)
  Records: 2  Duplicates: 0  Warnings: 0

  mysql> TABLE ex;
  +---------------------+
  | ts                  |
  +---------------------+
  | 2020-07-28 21:39:31 |
  | 2020-08-01 01:44:30 |
  +---------------------+
  2 rows in set (0.00 sec)

  mysql> SELECT ts, CAST(ts AT TIME ZONE 'UTC' AS DATETIME) AS ut FROM ex;
  +---------------------+---------------------+
  | ts                  | ut                  |
  +---------------------+---------------------+
  | 2020-07-28 21:39:31 | 2020-07-29 01:39:31 |
  | 2020-08-01 01:44:30 | 2020-08-01 05:44:30 |
  +---------------------+---------------------+
  2 rows in set (0.00 sec)
  ```

  자세한 정보와 예시는 *MySQL Manual*의 [`CAST()`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/cast-functions.html#function_cast) 함수 설명을 참조하십시오. (WL #12535)

## X 플러그인 관련 사항

- 특정 조건에서 X Protocol 연결을 종료하면 MySQL Server가 예기치 않게 중지될 수 있었습니다. (Bug #31671503)

## 추가되거나 변경된 기능

- 뷰에 대한 [`LOCK TABLES`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/lock-tables.html) 권한 검사가 개선되었습니다. (Bug #31304432, WL #14092)
- MySQL Server의 새로운 비동기 연결 페일오버 메커니즘을 사용하여, 복제본에서 해당 소스로의 기존 연결이 실패한 후 새 소스에 비동기(소스에서 복제본으로) 복제 연결을 자동으로 설정할 수 있습니다. 소스가 중지되거나 네트워크 장애로 인해 복제 I/O 스레드가 중지되면 연결이 페일오버됩니다. 비동기 연결 페일오버 메커니즘은 데이터를 공유하는 여러 MySQL 서버 또는 서버 그룹과 복제본의 동기화를 유지하는 데 사용할 수 있습니다. 복제 채널에 대해 비동기 연결 페일오버를 활성화하려면 해당 채널의 `CHANGE MASTER TO` 문에서 `SOURCE_CONNECTION_AUTO_FAILOVER=1`을 설정하고, `asynchronous_connection_failover_add_source` 및 `asynchronous_connection_failover_delete_source` 함수를 사용하여 해당 채널의 소스 목록을 설정하십시오. (WL #12649)
- 새로운 [`innodb_extend_and_initialize`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/innodb-parameters.html#sysvar_innodb_extend_and_initialize) 변수는 Linux에서 `InnoDB`가 file-per-table 및 general 테이블스페이스에 공간을 할당하는 방식을 설정할 수 있게 합니다. 기본적으로, 작업에서 테이블스페이스에 추가 공간이 필요하면 `InnoDB`는 테이블스페이스에 페이지를 할당하고 해당 페이지에 물리적으로 NULL을 씁니다. 새 페이지가 자주 할당되는 경우 이 동작은 성능에 영향을 줍니다. MySQL 8.0.22부터 Linux 시스템에서 [`innodb_extend_and_initialize`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/innodb-parameters.html#sysvar_innodb_extend_and_initialize)를 비활성화하여 새로 할당된 테이블스페이스 페이지에 NULL을 물리적으로 쓰지 않도록 할 수 있습니다. [`innodb_extend_and_initialize`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/innodb-parameters.html#sysvar_innodb_extend_and_initialize)가 비활성화된 경우, 공간은 NULL을 물리적으로 쓰지 않고 공간을 예약하는 `posix_fallocate()` 호출을 사용하여 할당됩니다.

  `posix_fallocate()` 작업은 원자적이지 않으므로, 테이블스페이스 파일에 공간을 할당하는 것과 파일 메타데이터를 업데이트하는 것 사이에 장애가 발생할 수 있습니다. 이러한 장애는 새로 할당된 페이지를 초기화되지 않은 상태로 남길 수 있으며, 그 결과 `InnoDB`가 해당 페이지에 액세스하려고 할 때 실패가 발생합니다. 이 시나리오를 방지하기 위해 `InnoDB`는 새 테이블스페이스 페이지를 할당하기 전에 redo 로그 레코드를 씁니다. 페이지 할당 작업이 중단되면, 복구 중에 redo 로그 레코드에서 해당 작업이 재실행됩니다. (WL #13782)

- MySQL grant 테이블에서 동시 DML 및 DDL 작업을 허용하기 위해, 이전에 MySQL grant 테이블에서 로우 잠금을 획득하던 읽기 작업은 이제 잠금 없는 읽기로 실행됩니다. 이제 MySQL grant 테이블에서 잠금 없는 읽기로 수행되는 작업에는 다음이 포함됩니다:

  - 임의의 트랜잭션 격리 수준을 사용하여, join 목록 및 서브쿼리를 통해 grant 테이블에서 데이터를 읽는 [`SELECT`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/select.html) 문 및 기타 읽기 전용 문입니다. 여기에는 [`SELECT... FOR SHARE`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/innodb-locking-reads.html) 문이 포함됩니다.
  - 임의의 트랜잭션 격리 수준을 사용하여, grant 테이블에서 데이터를 읽지만(join 목록 또는 서브쿼리를 통해) 해당 테이블을 수정하지 않는 DML 작업입니다.

  grant 테이블에서 데이터를 읽을 때 더 이상 로우 잠금을 획득하지 않는 문은 문 기반 복제를 사용하는 동안 실행되면 경고를 보고합니다.

  -[`binlog_format=mixed`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/replication-options-binary-log.html#sysvar_binlog_format)를 사용할 때, grant 테이블에서 데이터를 읽는 DML 작업은 이제 해당 작업을 혼합 모드 복제에서 안전하게 만들기 위해 바이너리 로그에 로우 이벤트로 기록됩니다.

  grant 테이블에서 데이터를 읽는 [`SELECT... FOR SHARE`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/innodb-locking-reads.html) 문은 이제 경고를 보고합니다. `FOR SHARE` 절을 사용하는 경우, grant 테이블에서는 읽기 잠금이 지원되지 않습니다.

  grant 테이블에서 데이터를 읽고 `SERIALIZABLE` 격리 수준을 사용하여 실행되는 DML 작업은 이제 경고를 보고합니다. `SERIALIZABLE` 격리 수준을 사용할 때 일반적으로 획득되는 읽기 잠금은 grant 테이블에서 지원되지 않습니다. (WL #14087)
- [`ALTER DATABASE`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/alter-database.html) 문은 이제 데이터베이스 및 그 안의 객체 수정을 허용할지 여부를 제어하는 `READ ONLY` 옵션을 지원합니다. 이 옵션은 데이터베이스 마이그레이션에 유용합니다. `READ ONLY`가 활성화된 데이터베이스는 작업 중에 데이터베이스가 변경될 수 있다는 우려 없이 다른 MySQL 인스턴스로 마이그레이션할 수 있기 때문입니다. [ALTER DATABASE Statement](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/alter-database.html)를 참조하십시오.

  [`SCHEMATA_EXTENSIONS`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/information-schema-schemata-extensions-table.html)라는 새 `INFORMATION_SCHEMA` 테이블은 데이터베이스 옵션을 표시합니다. 현재 이 테이블은 읽기 전용 데이터베이스에 대해 `READ ONLY=1`을 표시합니다. [The INFORMATION_SCHEMA SCHEMATA_EXTENSIONS Table](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/information-schema-schemata-extensions-table.html)을 참조하십시오. (WL #13369)

## 수정된 버그

- **InnoDB:** 히스토그램 샘플링에 대한 트랜잭션 지원과 관련된 코드가 제거되었으며, 여기에는 테스트 실패를 유발한 관련 어설션 코드가 포함됩니다. 히스토그램 샘플링에는 트랜잭션 지원이 필요하지 않습니다. (Bug #31787736)
- **InnoDB:** redo log archive log writer 스레드 쓰기 작업에 대해 암호화 정보가 설정되지 않았습니다. (Bug #31690196)
- **InnoDB:** `TTASEventMutex::exit` 함수가 ARM64에 대해 최적화되었습니다. 기여해 주신 Krunal Bauskar에게 감사드립니다. (Bug #31589019, Bug #100132)
- **InnoDB:** `InnoDB`가 `DISABLE_PSI_RWLOCK` CMake 옵션이 활성화된 상태에서 컴파일되지 않았습니다. (Bug #31578289)
- **InnoDB:** 불필요한 이전 레코드 버전 조회를 피하기 위해 히스토그램 샘플링에 대해 [`READ UNCOMMITTED`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/innodb-transaction-isolation-levels.html#isolevel_read-uncommitted)로 설정되는 트랜잭션 격리 수준이 샘플링 작업이 완료된 후 재설정되지 않았습니다. (Bug #31564407)
- **InnoDB:** 내부 임시 테이블의 클러스터형 인덱스를 업데이트한 쿼리가 잘못된 결과를 반환했습니다. 클러스터형 인덱스의 수정된 페이지가 flush list에 추가되지 않아, 수정된 페이지가 버퍼 풀에서 제거될 때 변경 사항이 손실되었습니다. (Bug #31560679)

  참조: 이 문제는 다음의 회귀입니다: Bug #29207450.

- **InnoDB:** TempTable 스토리지 엔진에 대해 정의된 Boost 라이브러리 빌드 의존성이 제거되었습니다. (Bug #31505048)
- **InnoDB:** 동일한 플랫폼의 동일한 타입에 대해 `__atomic_always_lock_free`가 true를 반환하는 동안 `ATOMIC_LLONG_LOCK_FREE` 값이 “sometimes lock-free”로 정의되게 하는 32비트 빌드의 Clang 컴파일러 문제를 처리하기 위한 우회 방법이 구현되었습니다. (Bug #31504609)
- **InnoDB:** 로우 형식이 명시적으로 정의되지 않았던 이전 버전의 MySQL에서 생성된 `REDUNDANT` 로우 형식 테이블은 `REDUNDANT` 로우 형식 인덱스 컬럼 크기 제한을 초과하는 인덱스 추가를 허용했습니다. (Bug #31479542, Bug #99791)
- **InnoDB:** 다중 값 인덱스로 정의된 컬럼에 대한 DML 작업이 실패를 발생시켰습니다. (Bug #31479282)
- **InnoDB:** 마스터 키 순환 중에 실패가 발생했습니다. 실행 취소 테이블스페이스 인메모리 객체가 너무 이르게 해제되었습니다. (Bug #31467626)
- **InnoDB:** 사용되지 않는 물리적 read ahead 코드가 병렬 읽기 인터페이스에서 제거되었습니다. (Bug #31429385)
- **InnoDB:** 마스터 키 순환 작업이 이미 잘린 실행 취소 테이블스페이스를 건너뛰지 못했으며, 이로 인해 서버 종료 시 어설션 실패가 발생했습니다. (Bug #31400195)

- **InnoDB:** 페이지 압축 테이블의 테이블스페이스를 임포트한 후 페이지가 더 이상 압축되지 않았으며, [`INFORMATION_SCHEMA.INNODB_TABLESPACES`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/information-schema-innodb-tablespaces-table.html) 메타데이터가 페이지가 압축되었다고 잘못 표시했습니다. 임포트 작업 중에 테이블의 압축 정보를 사용할 수 없었습니다. (Bug #31396947)
- **InnoDB:** instant DDL 작업을 수행한 후 롤백 및 업데이트 작업에서 assertion이 발생했습니다. (Bug #31391126)
- **InnoDB:** 로그 시스템(`log_sys`)의 샤딩된 읽기-쓰기 잠금이 CPU-bound 워크로드에서 성능 회귀를 일으켰습니다. (Bug #31389135)
- **InnoDB:** `UNIV_ENCRYPT_DEBUG` 옵션을 활성화하여 컴파일하면 컴파일 오류가 발생했습니다. (Bug #31369540)
- **InnoDB:** 파티셔닝된 테이블에 대한 DDL 작업이 실패를 일으킬 수 있었습니다. `TABLE_SHARE` 및 테이블 인스턴스 객체가 모든 파티션에 대해 불필요하게 열렸습니다. (Bug #31365127)

- **InnoDB:** In-place [`ALTER TABLE`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/alter-table.html) 작업에서 [`VARCHAR`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/char.html) 컬럼 콜레이션을 `utf8mb4`에서 `utf8mb4_bin`으로 변경하고 같은 컬럼에 인덱스를 추가한 후, [`VARCHAR`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/char.html) 컬럼에 대한 case-sensitive 쿼리가 잘못된 결과를 반환했습니다. [`VARCHAR`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/char.html) 컬럼 콜레이션은 데이터 딕셔너리에서는 변경되었지만, 메모리 내 테이블 객체에서는 변경되지 않았습니다. 따라서 [`VARCHAR`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/char.html) 컬럼에 생성된 인덱스가 오래된 컬럼 정보를 사용하여 비교에 이전에 정의된 콜레이션이 사용되었습니다. (Bug #31361838)
- **InnoDB:** 대형 암호화 및 압축 테이블에 대한 [`ALTER TABLE... IMPORT TABLESPACE`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/alter-table.html) 작업이 Page decompress failed after reading from disk 오류와 함께 실패했습니다. 복호화 작업이 암호화 중 사용된 암호화 블록 크기를 사용하지 않았습니다. 또한 암호화 프로세스는 압축된 길이를 고려하지 않았지만, 복호화 프로세스는 압축된 길이만 기준으로 데이터를 복호화합니다. (Bug #31313533)

- **InnoDB:** 동시 업데이트 작업 중 실패가 발생했습니다. 이 실패는 잘못된 이전 레코드 값 때문에 발생했습니다. (Bug #31205266, Bug #99286)
- **InnoDB:** 일반 테이블스페이스에 생성되고 `FULLTEXT` 인덱스로 정의된 테이블이 있는 인스턴스에서 MySQL 5.7에서 MySQL 8.0으로의 업그레이드가 실패했습니다. 테이블에 대한 올바른 데이터 딕셔너리 공간 ID를 확인할 수 없었습니다. (Bug #31154128, Bug #99211)
- **InnoDB:** [`SHOW ENGINE INNODB MUTEX`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/show-engine.html) 문을 처리하는 데 사용되는 함수가 새 뮤텍스를 동시에 추가하는 다른 스레드로부터 충분히 격리되지 않았습니다. (Bug #31105262)
- **InnoDB:** 버퍼 풀 페이지 I/O 완료 루틴 호출에 실패하여 고아 버퍼 풀 I/O 쓰기 페이지가 발생했습니다. (Bug #31073853)
- **InnoDB:** 버퍼 풀 플러시 목록의 끝에 있는 다수의 시스템 임시 테이블 페이지로 인해 성능 저하가 발생했습니다. 플러시 목록 스캔이 시스템 임시 테이블 페이지를 순회하는 동안 `flush_list_mutex`가 유지되었습니다. 이제 플러시 목록 스캔은 시스템 임시 테이블 페이지를 제외합니다. (Bug #31060470, Bug #98974)

- **InnoDB:** 버퍼 풀의 크기를 줄이는 동안 버퍼 제어 블록 구조체(`buf_block_t`)가 해제되어 assertion failure가 발생했습니다. 이 버그에 대한 수정은 Bug #20735882 / Bug #76343에 대한 수정의 중요한 측면도 백포트하며, 내부 `buf_block_is_uncompressed()` 함수를 `buf_pointer_is_block_field_instance()` 함수로 대체합니다. `buf_block_is_uncompressed()` 함수는 너무 많은 경우에 false를 반환하여 OLTP 쿼리 처리량에 영향을 주었습니다. (Bug #31036301, Bug #31389823)
- **InnoDB:** 병렬 읽기 스레드가 명시적 트랜잭션 중단에 응답하지 못했습니다. (Bug #31016076)
- **InnoDB:** `START TRANSACTION WITH CONSISTENT SNAPSHOT`으로 시작된 세션에서 범위 쿼리가 잘린 결과를 반환했습니다. 인덱스 읽기 시작 시점에 끝 범위 플래그가 재설정되지 않아 읽기가 중단되고 로우가 누락되었습니다. (Bug #30950714, Bug #98642)

  참조: 이 문제는 다음의 회귀입니다: Bug #23481444.
- **InnoDB:** 전체 텍스트 구문 검색에서 assertion failure가 발생했습니다. 기여해 주신 TXSQL(Tencent MySQL)에 감사드립니다. (Bug #30933728, Bug #31228694)

  참조: 이 문제는 다음의 회귀입니다: Bug #22709692.

- **InnoDB:** raw disk 파티션에서 시스템 테이블스페이스를 초기화하려고 시도하는 동안 실패가 발생했습니다. 또한 raw-disk 파티션 테이블스페이스에 대한 `INPLACE` DDL 작업이 `COPY` 알고리즘으로 전환되는 대신 오류와 함께 실패했습니다. (Bug #30867065, Bug #98091)
- **InnoDB:** LOB purge 코드(`lob::purge()`)가 B-tree mini-transaction(`btr_mtr`) 커밋 및 복원 작업 중 획득된 latch를 올바르게 처리하지 않았으며, 이로 인해 B-tree와 LOB mini-transaction 간의 충돌이 발생할 수 있었습니다. (Bug #30620011)
- **InnoDB:** 큰 테이블에서 장시간 실행되는 통계 계산 작업이 테이블 통계에 대한 액세스가 필요한 다른 작업을 차단하여 해당 작업들이 실패하게 했습니다. 동시 테이블 통계 액세스를 허용하는 새 통계 계산 mutex가 도입되었습니다. 기여해 주신 Kamil Holubicki에게 감사드립니다. (Bug #30607708)
- **InnoDB:** 두 연결이 동일한 트랜잭션 핸들러 객체를 사용하려고 시도하여 쿼리가 중단되었습니다. (Bug #30594501)

- **InnoDB:** [`innodb_fast_shutdown`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/innodb-parameters.html#sysvar_innodb_fast_shutdown) 설정이 0보다 큰 상태에서 서버를 종료하면 assertion failure가 발생했습니다. 이 assertion은 아직 롤백되지 않은 복구된 트랜잭션의 존재로 인해 발생했습니다. 빠른 종료 중에는 복구된 트랜잭션을 무시하도록 assertion 코드가 수정되었습니다. 빠른 종료로 인해 롤백되지 않은 복구된 트랜잭션이 남겨지는 경우 이제 오류 로그에 메시지가 기록됩니다. 느린 종료는 이제 복구된 트랜잭션이 롤백될 때까지 기다립니다. 그 밖의 다양한 종료 로직 개선 사항이 구현되었습니다. (Bug #30226841)

- **InnoDB:** MySQL 8.0.11에서 도입된 전용 로그 writer 스레드는 동시성이 낮은 시스템에서 CPU-bound 성능 회귀를 유발했습니다. 이 문제를 해결하기 위해, 새로운 [`innodb_log_writer_threads`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/innodb-parameters.html#sysvar_innodb_log_writer_threads) 변수는 전용 로그 writer 스레드를 비활성화할 수 있게 하며, 이에 따라 전용 로그 writer 스레드가 도입되기 전의 동작인 각 사용자 스레드가 로그 버퍼에서 시스템 버퍼로 redo 로그 레코드를 쓰고 시스템 버퍼에서 redo 로그 파일로 flush하도록 합니다. CPU 시간을 낭비하던 불필요한 로그 closer 스레드 제거와, 지나치게 공격적인 체크포인트 작업 및 과도한 flush 호출을 해결하기 위한 최적화를 포함하여 다른 redo 로깅 최적화도 구현되었습니다. 이 수정으로 해결된 문제는 `LOAD DATA` 성능 회귀에서도 나타났습니다. (Bug #30088404, Bug #30003849)

- **InnoDB:** 실패 후 잘못된 [`lower_case_table_names`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/server-system-variables.html#sysvar_lower_case_table_names) 설정으로 서버를 재시작하면 hang 상태가 발생했습니다. 시작 시 `InnoDB`는 트랜잭션이 롤백되기를 기다렸지만, 잘못된 [`lower_case_table_names`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/server-system-variables.html#sysvar_lower_case_table_names) 설정으로 인한 시작 검증 실패 때문에 롤백 스레드가 시작되지 않았습니다. (Bug #29833945)
- **Packaging; Group Replication:** MySQL Server Docker 이미지가 Group Replication 권장 포트(33061)를 노출하지 않았습니다. (Bug #31627536)
- **Packaging:** `client` 패키지에서 분리된 `client-plugins` RPM이 추가되었습니다. 여기에는 MySQL 클라이언트 애플리케이션용 공유 플러그인이 포함됩니다. (Bug #35162346)
- **Replication:** 이제 이전에는 허용되지 않았던, 저장 프로시저에서 [`gtid_purged`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/replication-options-gtids.html#sysvar_gtid_purged) 시스템 변수의 값을 설정할 수 있습니다. 저장 함수에서는 [`gtid_purged`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/replication-options-gtids.html#sysvar_gtid_purged)를 설정할 수 없습니다. (Bug #31571427)

- **Replication:** 복제 소스 서버가 종료된 후 재시작되면 해당 [`MEMORY`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/memory-storage-engine.html) 테이블은 비게 됩니다. 이 효과를 레플리카에 복제하기 위해, 시작 후 소스가 지정된 [`MEMORY`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/memory-storage-engine.html) 테이블을 처음 사용할 때, 해당 테이블을 비워야 함을 레플리카에 알리는 이벤트를 로그에 기록하며, 이를 위해 바이너리 로그에 해당 효과를 나타내는 문을 기록합니다. 이전에는 이것이 [`DELETE`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/delete.html) 문이었지만, 이제는 [`TRUNCATE TABLE`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/truncate-table.html) 문입니다. 레플리카 서버도 종료된 후 재시작될 때 이 문을 자체 바이너리 로그에 기록합니다. 이 문은 바이너리 로깅 형식이 `ROW`로 설정되어 있더라도 항상 statement 형식으로 로그에 기록되며, 서버에 `read_only` 또는 `super_read_only` 모드가 설정되어 있더라도 기록됩니다. (Bug #29848785, Bug #95496)

- **Replication:** 시스템 변수 [`session_track_gtids`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/server-system-variables.html#sysvar_session_track_gtids)가 멀티스레드 슬레이브에서 `OWN_GTID`로 설정된 경우, 슬레이브의 성능이 시간이 지남에 따라 저하되고 마스터보다 뒤처지기 시작했습니다. 원인은 각 트랜잭션 커밋 시 슬레이브의 워커 스레드가 기록한 GTID가 누적되어, 워커 스레드가 새 GTID를 삽입하는 데 걸리는 시간이 증가했기 때문이었습니다. 이제 멀티스레드 슬레이브의 워커 스레드에 대해 세션 상태 추적이 비활성화됩니다. 기여해 주신 Facebook에 감사드립니다. (Bug #29049207, Bug #92964)
- **Replication:** 로우 기반 복제를 사용할 때, 슬레이브가 동기화할 로우를 검색할 때 보이지 않는 인덱스를 사용할 수 있었습니다. (Bug #96148, Bug #30072179)
- **Group Replication:** 새 X Protocol 연결이 만들어진 후 세션이 생성되기 전에 Group Replication 알림이 발행되면 X Plugin이 예기치 않게 중지될 수 있었습니다. 이제 Group Replication 알림을 처리하는 디스패처 스레드는 세션 포인터가 유효한지 확인합니다. (Bug #31742798)
- **Group Replication:** 트랜잭션 쓰기 세트를 추가할 때 메모리 할당 문제에 대한 Group Replication 처리가 개선되었습니다. (Bug #31586243)

- **Group Replication:** 분산 복구 중 참여 멤버에서 원격 클로닝 절차가 진행되는 동안, Group Replication은 모든 멤버에 적용된 트랜잭션의 공통 집합을 식별할 때 참여 멤버의 클로닝 전 `gtid_executed` 값을 고려했습니다. 이는 그룹의 인증 정보 집합(Performance Schema 테이블 [`replication_group_member_stats`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/performance-schema-replication-group-member-stats-table.html)의 `count_transactions_rows_validating` 필드로 표시됨)에서 적용된 트랜잭션에 대한 가비지 컬렉션이 원격 클로닝 절차 중에 수행되지 않았음을 의미했습니다. 따라서 원격 클로닝 절차에 오랜 시간이 걸리면, 원격 클로닝 절차 후 참여 멤버가 다시 시작될 때 인증 정보가 참여 멤버로 전송하기에는 너무 커질 수 있었으며, 이 경우 오류가 발생하고 해당 멤버는 그룹에 참여할 수 없었습니다.

  이 문제를 방지하기 위해, Group Replication은 이제 모든 멤버에 적용된 트랜잭션의 공통 집합을 식별할 때 `ONLINE` 상태인 그룹 멤버만 고려합니다. 참여 멤버가 분산 복구 후 `ONLINE` 상태로 전환되면, 해당 멤버의 인증 정보는 멤버가 참여한 시점의 기증자 인증 정보로 업데이트되며, 이에 대한 가비지 컬렉션은 이후 라운드에서 수행됩니다.

  이전 릴리스에서 이 문제에 대한 해결 방법으로, 원격 클로닝 작업이 완료된 후 2분 동안 기다려 가비지 컬렉션 라운드가 수행되도록 하여 그룹의 인증 정보 크기를 줄이십시오. 그런 다음 참여 멤버에서 다음 명령문을 실행하여, 이전 인증 정보 집합 적용 시도를 중지하도록 하십시오:

  ```
  RESET SLAVE FOR CHANNEL group_replication_recovery;
  ```

  (Bug #31446381, Bug #99778)

- **Group Replication:** 통신 오류로 인해 그룹을 떠난 그룹 멤버가 자동 재참여 절차가 아직 진행 중인 동안 자동 재참여 시도 사이에 다시 연결될 수 있었으며, 이로 인해 해당 멤버에서 Group Replication이 기능할 수 없는 상태가 되었습니다. 이러한 상황을 방지하도록 Group Replication 오류 관리 및 멤버 상태 처리가 수정되었습니다. (Bug #31401797)
- **Microsoft Windows:** Windows에서 빌드가 `R:/`와 같은 파일 시스템 루트에서 수행되는 경우 빌드 대상이 실패할 수 있었습니다. (Bug #31315467)
- **JSON:** [`JSON_OBJECT()`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/json-creation-functions.html#function_json-object)는 `NULL` 값에 대해 항상 적절한 검사를 수행하지 않았습니다. (Bug #31393934)

- 새 [`WITH_SYSTEMD_DEBUG`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/source-configuration-options.html#option_cmake_with_systemd_debug) **CMake** 옵션은 활성화된 경우 systemd가 MySQL을 실행하는 데 사용되는 플랫폼에서 추가 systemd 디버깅 정보를 생성합니다. 기본값은 `OFF`입니다. (Bug #31788834)
- RPM 및 Debian 패키지의 경우 클라이언트 측 플러그인은 MySQL 8.0.21에서 서버 패키지에서 클라이언트 패키지로 이동되었습니다. 이로 인해 5.7 패키지에서 8.0 패키지로 업그레이드할 때 LDAP 인증 플러그인과 관련된 실패가 발생할 수 있었습니다. 이 문제를 방지하기 위해 패키징 조정이 이루어졌습니다. (Bug #31782612)

  참조: 이 문제는 다음의 회귀입니다: Bug #31123564, Bug #31336340.
- `log_sink_json` JSON 형식 오류 로그 싱크가 `ts` 키에 기록한 타임스탬프가 동일한 로그 메시지의 다른 타임스탬프와 같은 값을 갖지 않았습니다. (Bug #31749103)
- SASL LDAP 인증 플러그인의 Kerberos 인증이 티켓 부여 티켓 획득 실패를 올바르게 처리하지 않았습니다. (Bug #31727195)
- 일부 타사 라이브러리의 경우 링크 시간 최적화를 활성화하면 빌드 실패가 발생했습니다. (Bug #31701553, Bug #100410)
- 지나치게 긴 진단 메시지를 출력하면 서버가 예기치 않게 종료될 수 있었습니다. (Bug #31686926)

- 페이지 압축 테이블이 압축되지 않은 테이블로 클론되었습니다. 압축 플래그를 포함하는 관련 테이블스페이스 객체가 클론 작업 전에 초기화되지 않았습니다. (Bug #31677990, Bug #100243)
- 성공적인 LDAP 인증의 특정 경우로 인해 서버가 중단될 수 있었습니다. (Bug #31661437)
- 그룹화된 쿼리를 파생 테이블로 변환하는 동안, `WHERE` 절과 `HAVING` 절이 파생 테이블의 일부가 되었을 때 파생 테이블에 대해 조건 수가 업데이트되지 않았습니다. 이로 인해 `ref` 액세스를 위한 키를 생성하는 동안 메모리 할당이 감소했습니다. (Bug #31661309)
- MySQL 문자열 타입 중 하나로 정의되지 않은 테이블 컬럼과 함께 `LIKE`를 사용하여 값을 비교할 때, 서버가 때때로 예상된 오류를 발생시키지 않았습니다. (Bug #31659015)
- `acquire_related()` 서비스 함수는 오류를 반환해야 하는 일부 경우에 기본 서비스를 반환했습니다. (Bug #31655906)
- 부트스트래핑 모드에서 특정 다중 문장 트랜잭션이 예상치 못한 서버 동작을 유발할 수 있었습니다. (Bug #31650096)
- 원격 클론 작업에서 이전에 제공자 인스턴스에서 제거된 플러그인을 수신자에서 사용할 수 있는지 확인했습니다. 설치 제거된 플러그인에 대한 참조가 해제되지 않았습니다. 플러그인 불일치 및 사용 가능 여부와 관련된 오류 보고 문제도 해결되었습니다. (Bug #31639732, Bug #100244)

- debug 빌드에서 서버는 뷰를 생성하는 동안 서브쿼리를 평가하려고 했습니다. (Bug #31590301)

  참조: 이 문제는 다음의 회귀입니다: Bug #25466100.
- [`RAND()`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/mathematical-functions.html#function_rand)를 사용하는 조건은 그렇게 해도 안전한 경우, 즉 윈도잉 함수 또는 `GROUP BY`가 사용되지 않는 경우에도 푸시다운되지 않았습니다. (Bug #31587575)
- 조건을 파생 테이블로 푸시다운하는 동안 `WHERE FALSE` 또는 `WHERE TRUE`와 같은 상수 조건이 파생 테이블의 첫 번째 테이블로 푸시다운되었는데, 해당 조건은 파생 테이블과 아무 관련이 없으므로 이는 필요하지 않습니다. 이제 MySQL은 이러한 경우 상수 조건을 파생 테이블로 푸시다운하지 않습니다.

  또한 코드 검사 결과 조건의 컬럼을 파생 테이블 표현식으로 대체한 후 이 작업이 수행되지 않았음이 드러남에 따라, 이제 파생 테이블로 푸시다운해야 하는 조건에 대해 사용된 테이블이 업데이트됩니다. (Bug #31587493)
- `WHERE column > (... IN (SELECT...))`를 사용하는 쿼리가 때때로 범위 Optimizer에서 assertion을 트리거할 수 있었습니다. (Bug #31586906)

  참조: 이 문제는 다음의 회귀입니다: Bug #30473261.

- [`ANALYZE TABLE`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/analyze-table.html)은 로우의 존재 여부를 확인하는 시점과 삽입을 실행하는 시점 사이의 간격에 로우가 삽입되고, 통계 테이블이 동시에 업데이트되는 경우 Duplicate key 오류와 함께 실패할 수 있었습니다. 이제 [`ANALYZE TABLE`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/analyze-table.html)은 이 상황에서 해당 오류를 무시합니다. (Bug #31582758)
- 범위 Optimizer는 병합된 스캔을 수행하는 데 필요한 핸들러를 복제한 후 올바른 잠금 유형을 사용하지 않았으며, 대신 무조건 읽기 잠금을 사용했습니다. 이로 인해 여러 다른 시나리오에서 다양한 부작용이 발생했습니다.

  예를 들어, `FOR UPDATE`를 사용하는 [`SELECT`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/select.html)는 쓰기 잠금을 요청하지만, 인덱스 병합 스캔을 위해 핸들러를 복제한 후 범위 Optimizer는 읽기 잠금을 요청했으며, 이로 인해 불일치가 발생했습니다. 마찬가지로 데이터 딕셔너리 테이블의 경우, 이러한 테이블에 필요한 특수 처리로 인해 잠금 유형이 `LOCK_NONE`으로 설정되었습니다.

  이 문제가 발생하지 않도록 이제 핸들러의 원래 잠금 유형이 복제된 핸들러에서도 항상 사용되도록 보장합니다. (Bug #31582383)

- 일부 경우 [`subquery_to_derived`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/switchable-optimizations.html#optflag_subquery-to-derived) Optimizer 스위치가 활성화되었을 때 `ANY` 서브쿼리를 사용하는 쿼리가 잘못된 결과를 제공했습니다. (Bug #31566339)
- `FALSE AND condition`이 `FALSE`로 단순화될 때 *`condition`*에 할당된 임시 테이블 리소스가 이후에 항상 해제되지는 않았습니다. (Bug #31565009)
- `ULLONG_MAX`와 같은 값을 [`BIT(64)`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/bit-type.html) 컬럼에 삽입할 수 있었지만, 조회할 수는 없었습니다. (Bug #31564742, Bug #100053)
- 사용되지 않는 윈도우 정의를 제거하는 동안, `ORDER BY`의 일부였던 서브쿼리가 제거되지 않았습니다. 그런 다음 Optimizer가 테이블을 잠그지 않고 서브쿼리를 최적화하려고 했습니다. 이제 사용되지 않는 윈도우 정의를 제거할 때, 서버는 해당 정의의 일부로 존재하는 모든 서브쿼리를 정리합니다. (Bug #31518806)

  참조: 이 문제는 다음의 회귀입니다: Bug #27062031.
- MySQL 8.0.20에서 도입된 코딩 문제로 인해 클라이언트 애플리케이션이 종료 중 예기치 않게 종료될 수 있었습니다. (Bug #31515752)

  참조: 이 문제는 다음의 회귀입니다: Bug #27045306.

- ICU U_REGEX_NUMBER_TOO_BIG에서 MySQL [`ER_REGEX_NUMBER_TOO_BIG`](https://docs.oracle.com/cd/E17952_01/mysql-errors-8.0-en/server-error-reference.html#error_er_regex_number_too_big)로의 누락된 오류 코드 변환을 추가했습니다. (Bug #31514995)
- `filesort` 작업 중 병합이 `DISTINCT`를 사용한 쿼리에 대해 중복을 제거하지 못할 수 있었습니다. (Bug #31498664, Bug #99900)
- MySQL의 내부 `DYNAMIC_STRING` 클래스는 이전에 선형 방식, 즉 미리 정해진 바이트 수 단위로 메모리를 할당했습니다. 이 클래스는 이제 메모리를 지수적으로 할당하도록 수정되었으며, 반복적인 문자열 추가와 같은 작업을 더 효율적으로 수행할 수 있습니다. (Bug #31491799)
- `LOCK_mutex` 처리 오류로 인해 메모리 누수가 발생할 수 있었습니다. (Bug #31491146)
- 새로 추가된 콜레이션이 추가되지 않았으며 종료 시 예기치 않은 종료를 일으킬 수 있었습니다. (Bug #31470422)
- Windows에서 `GetTempFileName()` 함수에 의한 파일 이름 재사용으로 인해 어설션이 발생할 수 있었습니다. (Bug #31468590)
- `LATERAL` 서브쿼리가 잘못해서 안티조인으로 변환되었습니다. (Bug #31465717)
- `NATURAL JOIN` 평가가 함수형 인덱스에 의해 생성된 숨겨진 가상 컬럼과 의도치 않게 일치할 수 있었습니다. (Bug #31463511, Bug #99807)
- 1024바이트를 초과하여 사용하는 문자열 해시 조인 키의 정렬 키가 서버에서 올바르게 처리되지 않았습니다. (Bug #31437753)

- 서버는 정의에 `HAVING`이 포함된 뷰에서 삭제를 시도했으며, 이때 `HAVING` 절이 상수이고 true로 평가되었습니다. 하지만 정의의 일부로 `HAVING`이 있는 뷰는 업데이트 가능해서는 안 됩니다. (Bug #31429865)
- [`INFORMATION_SCHEMA.USER_ATTRIBUTES`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/information-schema-user-attributes-table.html) 테이블에 대한 권한 요구 사항이 잘못 검사되었습니다. (Bug #31427410)
- 내부 함수 `replace_index_subquery()`가 실패했을 때, 서버가 여전히 영향을 받는 서브쿼리에 대한 반복자 생성을 시도했습니다. 이제 이 함수는 대신 명확한 오류를 발생시킵니다. (Bug #31427072)
- `WHERE NOT EXISTS (SELECT const FROM table WHERE column=FROM_UNIXTIME(value)`를 사용하는 쿼리가 올바르게 처리되지 않았습니다. (Bug #31425664)
- 일부 경우에 `key_hint` 처리가 파생 테이블 및 내부 임시 테이블에 부적절하게 적용되었습니다. (Bug #31424455)
- 준비된 [`INSERT`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/insert.html) 문의 재실행이 뷰를 통한 삽입에서 실패할 수 있었습니다. (Bug #31417951)
- [`JSON`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/json.html) 스칼라 평가가 무한 루프에 들어갈 수 있었습니다. (Bug #31406724)
- `mysql.user` 테이블 로우의 `user_attributes` 컬럼이 부분 revoke에 의해 잘못 영향을 받을 수 있었습니다. (Bug #31405985)

- 부적절한 윈도우 함수 초기화로 인해 서버가 종료될 수 있었습니다. (Bug #31389573, Bug #31437834)
- 민감한 LDAP authentication 플러그인 시스템 변수는 이제 SQL 문에서 조회될 때 별표로 표시됩니다. (Bug #31388444, Bug #31391864)
- no-threads 연결 처리에서 실행되는 **mysql-test-run.pl** 테스트는 부적절한 리소스 그룹 초기화로 인해 ASAN 빌드에서 실패했습니다. 이 문제는 수정되었습니다. 기여해 주신 Tencent Technology의 Xiaoyu Wang에게 감사드립니다. (Bug #31378900, Bug #99609)
- SSL과 함께 `authentication_ldap_simple` authentication 플러그인을 사용하면 종료 중 세그멘테이션 폴트가 발생할 수 있었습니다. (Bug #31364927)
- 쿼리를 kill하면 해시 조인 iterator에서 잘못된 assertion이 발생할 수 있었습니다. (Bug #31361354)
- 일부 경우에 `LATERAL`이 아닌 외부 참조가 예상대로 읽기 전용으로 표시되지 않았습니다. (Bug #31359965)
- 고아 이벤트(데이터베이스가 더 이상 존재하지 않는 이벤트)에 대한 잘못된 참조로 인해 MySQL 5.7에서 MySQL 8.0으로 업그레이드할 때 실패가 발생했습니다. 서버는 이제 업그레이드 중 고아 이벤트가 발견되면 적절한 오류 메시지와 함께 실패합니다. 고아 stored routine에 대한 오류 메시지도 개정되었습니다. (Bug #31335554)

- [`create_admin_listener_thread`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/server-system-variables.html#sysvar_create_admin_listener_thread) 시스템 변수를 활성화하면 시작 중 서버 종료가 발생할 수 있었습니다. (Bug #31335279)
- [`ALTER TABLE`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/alter-table.html)을 사용하여 컬럼에 표현식 기본값을 추가한 후, 첫 번째 insert는 표현식이 insert 시점이 아니라 alter 시점에 평가된 것처럼 값을 삽입했습니다. (Bug #31330789, Bug #99513)
- LDAP 인증 플러그인이 사용자가 제공한 인증 방식을 허용된 방식과 제대로 비교하지 않았습니다. (Bug #31320532)
- 특정 뷰는 뒤따르는 [`USE`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/use.html) 문이 예기치 않은 서버 종료를 초래하게 할 수 있었습니다. (Bug #31311312)
- filesort가 버퍼를 정렬하고 `LIMIT`가 활성 상태일 때, 먼저 모든 로우를 정렬한 다음 제한 범위 안에 들어가지 않는 로우를 폐기했으며, 이로 인해 나중에 폐기될 것이 확실한 많은 로우를 정렬해야 했습니다. 이제 Optimizer는 실제로 필요한 로우만 정렬합니다. 내부 테스트에 따르면 이 변경으로 간단한 문자열 정렬 벤치마크에서 정렬 단계(`EXPLAIN ANALYZE`로 측정)가 최대 15% 빨라질 수 있습니다. (Bug #31303537)

- 동적 범위 스캔은 조인에서 첫 번째 테이블에서 가져온 각 로우에 대해 range optimizer를 실행하여, 해당 로우에서 사용할 수 있는 값을 사용해 두 번째 테이블에 범위 스캔을 선택할 수 있는지 여부를 결정합니다. 로우에 사용할 수 있는 인덱스가 없으면, 대신 테이블 스캔이 선택될 수 있습니다. 이 문제를 발생시킨 쿼리의 경우, 테이블 스캔이 한 번 선택된 뒤 non-covering 인덱스에 대한 범위 스캔이 이어지며, 동적 범위 반복자는 이 두 경우 모두에 사용되는 두 개의 읽기 세트를 가집니다. 이 중 테이블 스캔에 사용되는 하나는 쿼리 처리에 필요한 생성 컬럼의 베이스 컬럼을 포함하며, 다른 읽기 세트는 범위 스캔에 사용되는 읽기 세트에 베이스 컬럼을 포함하지 않습니다. 이는 covering 인덱스의 경우, hash join 또는 batched key access가 불필요한 컬럼을 추가하지 않도록 읽기 세트에 베이스 컬럼을 포함하지 않아야 하기 때문입니다. 이 문제는 두 번째 읽기 세트가 non-covering 인덱스에도 사용되어 assert가 발생했기 때문에 생겼습니다.

  이러한 일이 발생하지 않도록, 이제 동적 범위 반복자에서 테이블 읽기 세트를 초기화할 때 range optimizer가 non-covering 인덱스를 선택하면 베이스 컬럼이 포함되도록 보장합니다. (Bug #31280526)

  참조: 이 문제는 다음의 회귀입니다: Bug #30417361.

- 시간대 오프셋이 포함된 경우 [`TIMESTAMP`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/datetime.html)에 범위를 벗어난 값을 삽입할 수 있었습니다. (Bug #31239157)
- `keyring_hashicorp` keyring 플러그인은 키 작업에 대한 키 크기를 제한하지 않았습니다. (Bug #31205715)
- 이전 버전의 `zstd` 라이브러리에서는 [`-DWITH_ZSTD=system`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/source-configuration-options.html#option_cmake_with_zstd)으로 설정하면 실패했습니다. 이제 **CMake**는 `zstd` 버전을 확인하며, 컴파일에는 최소 1.0.0, 압축 검사를 실행하는 데는 1.2.0 이상을 요구합니다. (Bug #31174920, Bug #99241)
- 일부 경우에 Performance Schema 테이블에서 상태 변수 정보를 가져오고 시간 값이 포함된 컬럼별 정렬을 포함하는 [`SELECT`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/select.html)가 올바르게 처리되지 않았습니다. (Bug #31168097)
- 일부 경우에 [`ROUND()`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/mathematical-functions.html#function_round) 및 [`TRUNCATE()`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/mathematical-functions.html#function_truncate)는 예상대로 첫 번째 인수의 데이터 타입을 반환하지 않았습니다. 이 수정으로 이러한 함수의 반환 타입은 첫 번째 인수가 표시된 타입인 경우 다음 규칙을 따르도록 보장됩니다:

- 모든 정수 타입에 대해, 반환 타입은 [`BIGINT`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/integer-types.html)입니다.
  - 모든 부동 소수점 타입 또는 모든 비숫자 타입에 대해, 반환 타입은 [`DOUBLE`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/floating-point-types.html)입니다.
  - [`DECIMAL`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/fixed-point-types.html)의 경우, 반환 타입도 `DECIMAL`입니다.
  - 반환 값의 타입 속성도 첫 번째 인수에서 복사되지만, `DECIMAL`의 경우 두 번째 인수가 상수 값일 때는 예외입니다.
  - 원하는 소수 자릿수가 인수의 스케일보다 작으면, 결과의 스케일과 정밀도가 그에 따라 조정됩니다. 또한 `ROUND()` 함수의 경우, 유효 숫자 수를 증가시키는 반올림을 수용하기 위해 정밀도가 한 자리 확장됩니다. 두 번째 인수가 음수이면, 반환 타입은 스케일이 0이 되도록 조정되며, 이에 대응하는 정밀도를 가집니다.

  자세한 내용은 [`ROUND()`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/mathematical-functions.html#function_round) 함수 설명을 참조하십시오. (Bug #31128028)

- `SELECT... FOR SHARE` 문은 이제 [`SELECT`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/privileges-provided.html#priv_select) 권한만 필요합니다. 이전에는 [`SELECT`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/privileges-provided.html#priv_select) 권한이 [`DELETE`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/privileges-provided.html#priv_delete), [`LOCK TABLES`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/privileges-provided.html#priv_lock-tables), 또는 [`UPDATE`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/privileges-provided.html#priv_update) 권한 중 하나 이상과 함께 필요했습니다. (Bug #31096384, Bug #99101)
- `LIMIT` 절이 있고 첫 번째 로우가 아닌 다른 로우가 필요한 상관 서브쿼리의 조인에 대해 세미조인 전략이 선택되었으며, 이로 인해 `LIMIT` 절이 무시되고 유효하지 않은 로우가 반환되었습니다. 이제 이 유형의 조인과 함께 사용되는 `LIMIT`이 첫 번째 로우가 아닌 다른 로우 또는 둘 이상의 로우를 지정하는 경우, 세미조인 전략이 더 이상 사용되지 않습니다. (Bug #31096309)

- Bug #81009 수정 이후, [`read_only`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/server-system-variables.html#sysvar_read_only) 또는 [`super_read_only`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/server-system-variables.html#sysvar_super_read_only)가 활성화된 경우 Performance Schema 테이블을 자르는 권한 검사가 지나치게 제한적이어서, 적절한 테이블 권한을 가진 사용자에게도 자르기가 실패했습니다. (Bug #31080309, Bug #99072)

  References: 이 문제는 다음의 회귀입니다: Bug #81009.
- 윈도우 함수도 사용된 `ROLLUP` 포함 쿼리에서 `ORDER BY`가 예상대로 작동하지 않았습니다. (Bug #31073133)
- 일부 [`INSERT`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/insert.html) 문이 올바르게 처리되지 않았습니다. (Bug #31072198)
- 날짜 간격 계산이 오버플로는 검사했지만 언더플로는 검사하지 않았습니다. 이제 둘 다 검사합니다. (Bug #31054071)
- XA prepared 트랜잭션 롤백 XID 형식이 잘못된 경우, 트랜잭션은 오류를 보고하는 대신 [`XA COMMIT`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/xa.html) 및 [`XA ROLLBACK`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/xa.html) 문에 대해 복구된 상태로 남아 있었습니다(또는 디버그 빌드에서 assertion을 발생시켰습니다). (Bug #31030205)

- 역할을 통해 상속된 데이터베이스 수준 권한이 와일드카드 문자를 포함한 데이터베이스 이름에 대해 올바르게 처리되지 않았습니다. (Bug #31013538, Bug #98876)
- [`--local`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/mysqlimport.html#option_mysqlimport_local) 옵션이 지정되었을 때, **mysqlimport**가 `mysql_options()`에 대한 `MYSQL_OPT_LOAD_DATA_LOCAL_DIR` 옵션을 잘못 처리하여 효과가 없었습니다. (Bug #31001550)
- 특정 프리페어드 스테이트먼트가 예기치 않은 서버 종료를 유발할 수 있었습니다. (Bug #30943963)
- `MyISAM` 테이블에 대한 [`OPTIMIZE TABLE`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/optimize-table.html)이 테이블 크기 증가 및 쿼리 성능 저하를 유발할 수 있었습니다. `MyISAM` 테이블에 대한 [`REPAIR TABLE`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/repair-table.html)이 이전 [`OPTIMIZE TABLE`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/optimize-table.html)에서 생성된 `Table is already up to date` 상태가 손실되도록 할 수 있었습니다. (Bug #30869674, Bug #98511, Bug #29755517)
- **mysqlpump** 객체 검증에 제외된 데이터베이스의 객체가 포함되었습니다. (Bug #30819012)

- 월, 일 또는 둘 다에 0이 있고 시간대 오프셋도 있는 [`TIMESTAMP`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/datetime.html) 값을 삽입하면 assert가 발생했습니다. 이러한 값은 [`sql_mode`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/server-system-variables.html#sysvar_sql_mode) 설정과 관계없이 거부되어야 하며, 이제 거부됩니다. (Bug #30786762)

  References: 참고: Bug #31239157.
- 역할을 사용하여 부여된 권한이 컬럼 권한 수준에서 잘못 처리될 수 있었습니다. (Bug #30660403, Bug #97971)
- 일부 경우에 [`TIME`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/time.html) 값을 `NULL`과 비교하면 assertion이 발생했습니다. (Bug #30324587)

  References: 이 문제는 다음의 regression입니다: Bug #25949639.
- LDAP 인증 플러그인이 CA 검증을 잘못 적용했으며, 이로 인해 잘못된 CA가 사용될 수 있었습니다. (Bug #30220357)
- [`sort_buffer_size`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/server-system-variables.html#sysvar_sort_buffer_size) 및 [`max_sort_length`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/server-system-variables.html#sysvar_max_sort_length)가 정렬 버퍼당 허용되는 최대 키 수에 대한 내부 제한이 0으로 설정되도록 하는 값으로 설정된 경우, `ORDER BY` 쿼리가 올바르게 실행되지 않았습니다. (Bug #30175483)

- 전체 텍스트 검색 쿼리에서 중첩된 인수가 많으면 오류가 발생했습니다. (Bug #29929684)
- Performance Schema의 메모리 사용량이 잘못 보고될 가능성이 수정되었습니다. (Bug #29912403)
- [`explicit_defaults_for_timestamp`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/server-system-variables.html#sysvar_explicit_defaults_for_timestamp)가 비활성화되어 있고 [`TIMESTAMP`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/datetime.html) `NOT NULL`로 선언된 생성 컬럼에 `NULL`이 삽입되면, 서버는 삽입된 값을 [`CURRENT_TIMESTAMP`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/date-and-time-functions.html#function_current-timestamp)로 변환하려고 시도했습니다. 이제 이러한 삽입은 [`ER_BAD_NULL_ERROR`](https://docs.oracle.com/cd/E17952_01/mysql-errors-8.0-en/server-error-reference.html#error_er_bad_null_error)와 함께 거부됩니다. (Bug #29449518)
- [`SET_VAR`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/optimizer-hints.html#optimizer-hints-set-var) 힌트가 시스템 변수 설정으로 지정된 부동 소수점 값을 허용하지 않았습니다. (Bug #29349748)

- 이전에는 [`STR_TO_DATE()`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/date-and-time-functions.html#function_str-to-date)에 format 인수로 `NULL`이 사용되면 관련 없는 경고가 출력되었습니다. 이제 `NULL`이 전달되면 이 함수는 `NULL`을 반환합니다. (Bug #27265863)
- 일부 경우에 [`IS NULL`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/comparison-operators.html#operator_is-null)을 잘못 사용하면 유효하지 않은 인수에 대한 여러 경고가 생성되었습니다. (Bug #27264652)
- 특정 prepared statement를 실행할 때 파생 테이블의 [`SELECT`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/select.html) 목록 컬럼을 참조하는 `ORDER BY` 컬럼 해석이 올바르게 수행되지 않았습니다. (Bug #26808862)
- 조건에서 생성 컬럼이 참조된 다중 테이블 [`UPDATE`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/update.html) 문에 [`EXPLAIN`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/explain.html)을 사용할 때, 해당 테이블이 실제로 업데이트되었는지 여부와 관계없이 출력에는 항상 이 컬럼을 포함하는 테이블이 업데이트되는 것으로 표시되었습니다. (Bug #22671310)
- SQL 계층이 임시 테이블에서 수행할 작업 유형에 대해 `InnoDB`에 잘못된 정보를 전달하면 assertion이 발생할 수 있었습니다. (Bug #22503696)

- 이 구문은 모든 기본값을 사용하여 로우를 삽입하기 위해 베이스 테이블에서는 작동하지만, 뷰에서는 실패했습니다:

  ```
  INSERT INTO name () VALUES ();
  ```

  (Bug #15988466, Bug #67863)

- 일부 경우에는 [`use_invisible_indexes`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/switchable-optimizations.html#optflag_use-invisible-indexes) Optimizer 스위치가 `OFF`로 설정되지 않은 경우에도, 보이지 않는 인덱스가 인덱스 힌트에 사용되면 서버가 오류를 발생시켰습니다. (Bug #100024, Bug #31550839)
- [`REGEXP_LIKE()`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/regexp.html#function_regexp-like)와 같은 정규 표현식 함수는 바이너리 문자열 인수를 사용할 때 일관되지 않은 결과를 산출했습니다. 이제 이러한 함수는 오류와 함께 바이너리 문자열을 거부합니다. (Bug #98950, Bug #98951, Bug #31031886, Bug #31031888)

- 조건자에 지정된 범위 값이 해당 값과 비교되는 컬럼의 데이터 타입과 호환되지 않는 경우, range optimizer는 범위 값을 반올림하고 특정 플래그를 할당하여 반올림 때문에 범위에 적합한 로우가 제외되지 않도록 합니다. 보고된 문제를 유발한 특정 쿼리에서는 [`INT`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/integer-types.html) 타입의 `id`라는 컬럼이 `id NOT IN (-0.1, 0.1)`을 사용하여 테스트되었으며, 테스트되는 값이 정수로 반올림되어 조건자가 그에 따라 `NOT IN (0,0)`으로 처리되었습니다. 그런 다음 optimizer는 이를 `id < 0` 및 `0 < id < 0` 인터벌로 처리하지만, 이 경우 비교할 값으로 0을 포함하는 로우 다음부터 읽기가 시작되어야 함을 나타내는 값으로 플래그도 설정했습니다. 이제 이러한 경우에는 반올림된 값이 올바르게 처리되도록 플래그가 설정됩니다. (Bug #98826, Bug #30988735)

  참조: 이 문제는 다음의 회귀입니다: Bug #80244, Bug #22661012.

- 업데이트 가능한 부분과 그렇지 않은 부분을 포함하는 조인을 기반으로 하는 뷰의 경우, 이 뷰에서 업데이트할 수 없는 컬럼을 업데이트하려고 시도할 때 생성되는 오류 메시지가 문제가 된 [`UPDATE`](https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/update.html) 문에 실제로 명명된 뷰 대신 소스 테이블 또는 뷰를 참조했습니다. (Bug #80655, Bug #22891840)
