CREATE TABLE AS SELECT 동안 MySQL 잠금


10

다음 (더미) 쿼리를 실행 중입니다.

CREATE TABLE large_temp_table AS 
    SELECT a.*, b.*, c.* 
    FROM a
    LEFT JOIN b ON a.foo = b.foo
    LEFT JOIN c ON a.bar = c.bar

쿼리를 실행하는 데 10 분이 걸린다고 가정하십시오. 테이블 a, b 또는 c가 실행되는 동안 값을 업데이트하려고하면 위 쿼리가 먼저 완료 될 때까지 기다립니다. 이 잠금을 피하고 싶습니다 (데이터 일관성은 중요하지 않습니다). 어떻게하면 되나요?

사용 : MySQL 5.1.41 및 InnoDB 테이블

ps 세트 트랜잭션 격리 레벨 읽기 커밋되지 않음; 행동에는 변화가 없다

업데이트 쿼리가 실행되는 동안 SHOW ENGINE INNODB STATUS의 출력은 다음과 같습니다 (목적으로 매우 느린 쿼리를 만들었습니다)

=====================================
120323 15:26:29 INNODB MONITOR OUTPUT
=====================================
Per second averages calculated from the last 8 seconds
----------
SEMAPHORES
----------
OS WAIT ARRAY INFO: reservation count 1470, signal count 1468
Mutex spin waits 0, rounds 7525, OS waits 112
RW-shared spins 803, OS waits 364; RW-excl spins 1300, OS waits 959
------------
TRANSACTIONS
------------
Trx id counter 0 3145870
Purge done for trx's n:o < 0 3141943 undo n:o < 0 0
History list length 22
LIST OF TRANSACTIONS FOR EACH SESSION:
---TRANSACTION 0 0, not started, OS thread id 2958192640
MySQL thread id 7942, query id 69073 localhost root
SHOW ENGINE INNODB STATUS
---TRANSACTION 0 3145869, ACTIVE 20 sec, OS thread id 2955325440, thread declared inside InnoDB 343
mysql tables in use 1, locked 1
6 lock struct(s), heap size 1024, 162 row lock(s)
MySQL thread id 7935, query id 69037 localhost root Copying to tmp table
CREATE TABLE 1_temp_foo AS
                       SELECT SQL_NO_CACHE
                           a.*
                       FROM
                           crm_companies AS a
                       LEFT JOIN users b ON a.zipcode = b.uid
                       LEFT JOIN calc_base_materials c ON a.zipcode = c.material_id
                       LEFT JOIN calc_base_material_langtext d ON a.zipcode = d.material_id
                       LEFT JOIN crm_people e ON a.zipcode = e.telephone1_number
                       ORDER BY a.country, a.name1
--------
FILE I/O
--------
I/O thread 0 state: waiting for i/o request (insert buffer thread)
I/O thread 1 state: waiting for i/o request (log thread)
I/O thread 2 state: waiting for i/o request (read thread)
I/O thread 3 state: waiting for i/o request (write thread)
Pending normal aio reads: 0, aio writes: 0,
ibuf aio reads: 0, log i/o's: 0, sync i/o's: 0
Pending flushes (fsync) log: 0; buffer pool: 0
27579 OS file reads, 613 OS file writes, 392 OS fsyncs
0.00 reads/s, 0 avg bytes/read, 0.00 writes/s, 0.00 fsyncs/s
-------------------------------------
INSERT BUFFER AND ADAPTIVE HASH INDEX
-------------------------------------
Ibuf: size 1, free list len 5, seg size 7,
0 inserts, 0 merged recs, 0 merges
Hash table size 34679, node heap has 9 buffer(s)
0.00 hash searches/s, 0.00 non-hash searches/s
---
LOG
---
Log sequence number 1 2030837110
Log flushed up to   1 2030837110
Last checkpoint at  1 2030837110
0 pending log writes, 0 pending chkp writes
231 log i/o's done, 0.00 log i/o's/second
----------------------
BUFFER POOL AND MEMORY
----------------------
Total memory allocated 21060366; in additional pool allocated 1048576
Dictionary memory allocated 2897304
Buffer pool size   512
Free buffers       0
Database pages     503
Modified db pages  0
Pending reads 0
Pending writes: LRU 0, flush list 0, single page 0
Pages read 36022, created 166, written 504
0.00 reads/s, 0.00 creates/s, 0.00 writes/s
Buffer pool hit rate 1000 / 1000
--------------
ROW OPERATIONS
--------------
1 queries inside InnoDB, 0 queries in queue
1 read views open inside InnoDB
Main thread id 2957578240, state: waiting for server activity
Number of rows inserted 2022, updated 7, deleted 13, read 528536
0.00 inserts/s, 0.00 updates/s, 0.00 deletes/s, 8.00 reads/s
----------------------------
END OF INNODB MONITOR OUTPUT
============================

업데이트 2

쿼리가 실행되는 동안 b, c 또는 d를 업데이트하려고 할 때 INNODB STATUS는 다음과 같습니다.

=====================================
120323 16:12:58 INNODB MONITOR OUTPUT
=====================================
Per second averages calculated from the last 27 seconds
----------
SEMAPHORES
----------
OS WAIT ARRAY INFO: reservation count 2959, signal count 2957
Mutex spin waits 0, rounds 27587, OS waits 426
RW-shared spins 1321, OS waits 516; RW-excl spins 2578, OS waits 1855
------------
TRANSACTIONS
------------
Trx id counter 0 3145998
Purge done for trx's n:o < 0 3145994 undo n:o < 0 0
History list length 0
LIST OF TRANSACTIONS FOR EACH SESSION:
---TRANSACTION 0 0, not started, OS thread id 2958602240
MySQL thread id 7990, query id 69621 localhost root
SHOW INNODB STATUS
---TRANSACTION 0 3145997, ACTIVE 35 sec, OS thread id 2955325440, thread declared inside InnoDB 227
mysql tables in use 1, locked 0
MySQL thread id 7984, query id 69594 localhost root Copying to tmp table
CREATE TABLE 1_temp_foo AS
                       SELECT SQL_NO_CACHE
                           a.*
                       FROM
                           crm_companies AS a
                       LEFT JOIN users b ON a.zipcode = b.uid
                       LEFT JOIN calc_base_materials c ON a.zipcode = c.material_id
                       LEFT JOIN calc_base_material_langtext d ON a.zipcode = d.material_id
                       LEFT JOIN crm_people e ON a.zipcode = e.telephone1_number
                       ORDER BY a.country, a.name1
Trx read view will not see trx with id >= 0 3145998, sees < 0 3145998
--------
FILE I/O
--------
I/O thread 0 state: waiting for i/o request (insert buffer thread)
I/O thread 1 state: waiting for i/o request (log thread)
I/O thread 2 state: waiting for i/o request (read thread)
I/O thread 3 state: waiting for i/o request (write thread)
Pending normal aio reads: 0, aio writes: 0,
ibuf aio reads: 0, log i/o's: 0, sync i/o's: 0
Pending flushes (fsync) log: 0; buffer pool: 0
54447 OS file reads, 1335 OS file writes, 509 OS fsyncs
0.00 reads/s, 0 avg bytes/read, 0.00 writes/s, 0.00 fsyncs/s
-------------------------------------
INSERT BUFFER AND ADAPTIVE HASH INDEX
-------------------------------------
Ibuf: size 1, free list len 5, seg size 7,
584 inserts, 584 merged recs, 4 merges
Hash table size 34679, node heap has 1 buffer(s)
0.00 hash searches/s, 0.00 non-hash searches/s
---
LOG
---
Log sequence number 1 2060137545
Log flushed up to   1 2060137545
Last checkpoint at  1 2060137545
0 pending log writes, 0 pending chkp writes
338 log i/o's done, 0.00 log i/o's/second
----------------------
BUFFER POOL AND MEMORY
----------------------
Total memory allocated 20799534; in additional pool allocated 1047808
Dictionary memory allocated 2897304
Buffer pool size   512
Free buffers       0
Database pages     511
Modified db pages  0
Pending reads 0
Pending writes: LRU 0, flush list 0, single page 0
Pages read 70769, created 661, written 3156
0.00 reads/s, 0.00 creates/s, 0.00 writes/s
Buffer pool hit rate 1000 / 1000
--------------
ROW OPERATIONS
--------------
1 queries inside InnoDB, 0 queries in queue
2 read views open inside InnoDB
Main thread id 2957578240, state: waiting for server activity
Number of rows inserted 2022, updated 66643, deleted 13, read 626517
0.00 inserts/s, 0.00 updates/s, 0.00 deletes/s, 7.59 reads/s
----------------------------
END OF INNODB MONITOR OUTPUT
============================

그리고 실제 공개 프로세스 목록이 있습니다

프로세스 목록

답변:


10

이 질문은 SHOW INNODB STATUS\G

CREATE TABLE 1_temp_foo AS 
                   SELECT SQL_NO_CACHE 
                       a.* 
                   FROM 
                       crm_companies AS a 
                   LEFT JOIN users b ON a.zipcode = b.uid 
                   LEFT JOIN calc_base_materials c ON a.zipcode = c.material_id 
                   LEFT JOIN calc_base_material_langtext d ON a.zipcode = d.material_id 
                   LEFT JOIN crm_people e ON a.zipcode = e.telephone1_number 
                   ORDER BY a.country, a.name1 

이 쿼리는 당신이 생각하지 못한 세 가지를 결합하기 때문에 크립을 제공합니다.

  • InnoDB는 귀하의 초기 전제에 기초합니다 : Using: MySQL 5.1.41 and InnoDB Tables
  • MyISAM도 관련되어 있습니다. MyISAM이 관련된 이유는 무엇입니까? 모든 내부 TEMP 테이블은 MyISAM입니다 !!! 결과 조인은 임시 테이블이 채워질 때 InnoDB로 변환되어야하는 MyISAM 테이블입니다. MyISAM 테이블의 기본 잠금 수준은 무엇입니까? 테이블 레벨 잠금.
  • 새로 작성된 테이블이 존재해야하므로 DDL이 관련됩니다. 임시 테이블이 채워지고 InnoDB로 변환되고 마지막으로 이름이 변경 될 때까지 새 테이블이 표시되지 않습니다 1_temp_foo.

주목할만한 또 다른 부작용이 있습니다. 당신이 할 때

CREATE TABLE tblname AS SELECT ...

결과 테이블에는 인덱스가 없습니다.

잠금 문제를 우회하는 데 도움이 될만한 것이 있습니다. 먼저 테이블을 별도의 쿼리로 만든 다음 채 웁니다. 임시 테이블을 만들기위한 두 가지 옵션이 있습니다.

옵션 # 1 : 같은 레이아웃으로 테이블을 만들어보십시오

CREATE TABLE 1_temp_foo LIKE crm_companies;

이렇게하면 1_temp_foo원래 테이블과 정확히 동일한 인덱스 및 스토리지 엔진을 갖도록 테이블이 작성됩니다 crm_companies.

옵션 # 2 : 인덱스가없는 동일한 스토리지 엔진만으로 테이블을 생성하십시오.

CREATE TABLE 1_temp_foo SELECT * FROM crm_companies WHERE 1=2;
ALTER TABLE 1_temp_foo ENGINE=InnoDB;

테이블을 만든 후 (어느 쪽이든 선택) 이제 다음과 같이 테이블을 채울 수 있습니다.

INSERT INTO 1_temp_foo
SELECT SQL_NO_CACHE a.*                   
FROM                   
    crm_companies AS a                   
    LEFT JOIN users b ON a.zipcode = b.uid                   
    LEFT JOIN calc_base_materials c ON a.zipcode = c.material_id                   
    LEFT JOIN calc_base_material_langtext d ON a.zipcode = d.material_id                   
    LEFT JOIN crm_people e ON a.zipcode = e.telephone1_number                   
    ORDER BY a.country, a.name
;

이제이 쿼리는 반복 가능한 읽기에 데이터를 사용할 수 있도록 행 수준 잠금을 생성해야합니다. 다시 말해, 이것은 트랜잭션 쿼리입니다.

경고

OPTION # 2는 OPTION # 1보다 장점이 있습니다

  • 장점 # 1 : crm_companies에 외래 키 제약 조건이 있으면 OPTION # 1은 실제로 불가능합니다. 단순성을 위해 OPTION # 2를 선택해야합니다.
  • 장점 # 2 : OPTION # 2는 사용자 정의 인덱스가없는 테이블을 생성하므로 테이블이 OPTION # 1을 통해 만들어진 경우보다 테이블이 더 빨리로드되어야합니다.

2

트랜잭션 격리 수준을 READ COMMITTED (또는 COMM UNCOMMITTED)로 설정하는 것 외에도 이진 로그 형식을 MIXED 또는 ROW로 설정해야합니다. STATEMENT 기반 복제는 모든 유형의 "안전"을 보장하기 위해이 유형의 명령문을 잠급니다. innodb_locks_unsafe_for_binlog = 1을 임시로 설정할 수도 있지만, 동기화되지 않은 슬레이브로 끝날 수 있습니다.

SET binlog_format = ROW;
CREATE TABLE ... SELECT ...

불행히도 이것은 작동하지 않습니다 :(
Clops

1
CREATE TABLE 문이 실행될 때 SHOW ENGINE INNODB STATUS의 출력은 무엇입니까?
Aaron Brown

1
또한 커밋되지 않은 읽기가 아니라 읽기 커밋을 사용하고 있는지 확인하십시오. 5.1.47까지 수정되지 않은이 버그가 발생했을 수 있습니다. bugs.mysql.com/bug.php?id=48607
Aaron Brown

1
이상하다. 외래 키가 있습니까? 행을 업데이트하는 동안 INNODB STATUS를 게시 할 수 있습니까? 최신 버전의 MySQL에서 시도해 보셨습니까? (내 생각에는 배포판과 함께 제공되므로 5.1.41을 사용하고 있다고 생각합니까?)
Aaron Brown

1
users 테이블이 InnoDB인지 확실합니까? SHOW ENGINE INNODB STATUS 출력에 업데이트가 나타나지 않고 프로세스 목록에 일반적으로 MyISAM 테이블의 결과 인 잠금으로 표시됩니다. @RolandoMySQLDBA의 답변으로 문제가 해결되어 기쁘지만 여기에 다른 문제가 있다고 생각합니다.
Aaron Brown
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.