본문 바로가기

DB & Storage & Stream/Mysql, MariaDB

[Database/MySQL, MariaDB] 무한 로딩 쿼리(Huge query) 중단하기

무한 로딩 쿼리(Huge query)

Huge query 실행으로 인해 MySQL(또는 MariaDB) 클라이언트가 무한 로딩에 걸리는 상태가 간혹 발생합니다. 이 경우 해당 클라이언트에서  락이 걸려 다른 쿼리를 실행하더라도 앞서 실행한 쿼리의 종료를 무한히 기다리게 됩니다. 만약 해당 쿼리가 실수로 실행되었고, 실행을 취소하고자 한다면 다음 방법이 있습니다.

  • SequalPro, Workbench 등 MySQL 클라이언트를 재시작합니다.
  • 아파치 또는 MySQL 서버를 재시작합니다.
  • 락을 발생시키는 쿼리를 찾아서 관련 프로세스를 종료합니다.

MySQL 클라이언트 재시작으로 해결이 안되거나, MySQL 서버의 종료가 불가능한(서비스 환경 등) 경우 관련 프로세스를 종료하는 방법으로 해결해야 합니다.

문제의 프로세스 확인

터미널에서 다음 mysql 명령어를 통해 활성화 중인 프로세스 리스트를 출력합니다.

$ mysqladmin processlist -u root -p

또는 터미널에서 루트 계정으로 MySQL 서버에 로그인하여 다음 쿼리를 실행합니다(MySQL 명령문은 대문자로 작성합니다). 

$ mysql -u root -p
Enter password: 
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 29231
Server version: 10.6.3-MariaDB-log Homebrew

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MariaDB [(none)]> SHOW PROCESSLIST;

실행 중인 프로세스 목록은 다음과 같이 출력됩니다. 

+-------+------+-----------------+----------+---------+------+--------------+------------------+----------+
| Id    | User | Host            | db       | Command | Time | State    	| Info             | Progress |
+-------+------+-----------------+----------+---------+------+--------------+------------------+----------+
| 16    | root | localhost:51197 |          | Sleep   | 34   |          	|                  | 0.000    |
| 29229 | root | localhost       | test     | Query   | 3889 | Sending data	| select * from .. | 0.000    |
| 29230 | root | localhost       |          | Query   | 0    | starting		| show processlist | 0.000    |
+-------+------+-----------------+----------+---------+------+--------------+------------------+----------+
  • Id
    연결 프로세스에 대한 식별자로써, MySQL이 관리하는 스레드 번호입니다.
  • User
    명령문 또는 쿼리를 발행한 MySQL 사용자입니다.
  • Host
    명령문 또는 쿼리를 실행하고 있는 TCP/IP 연결을 통한 호스트 이름입니다. 어떤 클라이언트가 무엇을 수행하고 있는지 쉽게 알 수 있도록 host_name:client_port 형식으로 구성되어 있습니다.
  • db
    스레드의 기본 데이터베이스 또는 아무것도 선택하지 않았다면 NULL입니다.
  • Command
    스레드가 클라이언트를 대신하여 실행하는 명령문 또는 쿼리에 대한 유형입니다. 만약 세션이 Idle 상태라면 Sleep으로 표기됩니다.
  • Time
    스레드가 현재 상태에 머물고 있었던, 또는 머물고 있는 시간입니다(단위:초). Replica에서는 마지막으로 복제된 이벤트의 타임스탬프와 복제된 호스트의 실시간 시간 차입니다(단위:초).
  • State
    스레드가 수행하는 작업을 나타내는 상태입니다.  대부분의 상태는 매우 빠르게 변화하며, 스레드가 몇 초 이상 동일한 상태를 유지하는 경우 문제가 있을 수 있습니다.
  • Info
    스레드가 실행 중인 명령문 또는 쿼리입니다. 실행 중인 내용이 없는 경우 NULL입니다.

프로세스 리스트에서 Info 컬럼을 참고하여 자신이 실행한 쿼리문을 처리 중인 프로세스를 찾으면 됩니다. 위의 예시에서 프로세스 Id 29229를 살펴보면, 스레드가 3889초 동안 유지되었고 현재 데이터를 보내고 있는 상태인 것을 알 수 있습니다. 상당히 큰 데이터에 대해서 Huge query 하였기에 Select 쿼리 결과를 아직도 전송하고 있는 상태입니다.

프로세스 종료

락을 유발한 프로세스를 종료하기 위해서는 다음 명령문을 실행합니다.

$ mysqladmin kill [프로세스 ID]

또는 MySQL 서버에 로그인되어 있다면 다음 명령문을 실행하여 동일한 결과를 얻을 수 있습니다.

KILL [프로세스 ID];

명령문이 제대로 실행되었다면, 다시 프로세스 목록을 확인하여 해당 프로세스가 종료되었는지 확인합니다. 프로세스가 종료되었다면 다시 MySQL 클라이언트를 실행하여 간단한 쿼리를 실행합니다. 이전과 달리 락에 걸리지 않고 쿼리가 실행됩니다.

+-------+------+-----------------+----------+---------+------+--------------+------------------+----------+
| Id    | User | Host            | db       | Command | Time | State    	| Info             | Progress |
+-------+------+-----------------+----------+---------+------+--------------+------------------+----------+
| 16    | root | localhost:51197 |          | Sleep   | 34   |          	|                  | 0.000    |
| 29230 | root | localhost       |          | Query   | 0    | starting		| show processlist | 0.000    |
+-------+------+-----------------+----------+---------+------+--------------+------------------+----------+