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 ถึงเกี่ยวข้อง? แท็บเล็ตภายในทั้งหมดเป็น MyISAM !!! การรวมผลลัพธ์เป็นตาราง MyISAM ที่ต้องถูกแปลงเป็น InnoDB เมื่อตารางชั่วคราวได้รับการเติมข้อมูล ระดับการล็อคเริ่มต้นสำหรับตาราง MyISAM คืออะไร ล็อคระดับตาราง
  • DDL มีส่วนเกี่ยวข้องเนื่องจากต้องสร้างตารางที่สร้างขึ้นใหม่ ที่ตารางใหม่จะไม่เป็นที่ประจักษ์จนตาราง temp เป็นประชากรแปลง InnoDB 1_temp_fooและเปลี่ยนชื่อเป็นที่สุด

มีผลข้างเคียงอื่นที่ควรค่าแก่การสังเกต เมื่อคุณทำ

CREATE TABLE tblname AS SELECT ...

ตารางผลลัพธ์ไม่มีดัชนี

ฉันมีสิ่งที่คุณอาจพบว่ามีประโยชน์ในการหลีกเลี่ยงปัญหาการล็อค มันเกี่ยวข้องกับการสร้างตารางก่อนเป็นแบบสอบถามแยกต่างหากจากนั้นเติมมัน มีสองตัวเลือกในการสร้างตารางชั่วคราวของคุณ:

OPTION # 1 : ลองสร้างตารางด้วยเค้าโครงเดียวกัน

CREATE TABLE 1_temp_foo LIKE crm_companies;

นี้จะสร้างตารางที่จะมีการจัดทำดัชนีเดียวกันแน่นอนและเครื่องมือจัดเก็บเป็นตารางเดิม1_temp_foocrm_companies

OPTION # 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 มีข้อ จำกัด ของคีย์ต่างประเทศตัวเลือก # 1 นั้นเป็นไปไม่ได้จริงๆ คุณจะต้องเลือก OPTION # 2 เพื่อความเรียบง่าย
  • ข้อได้เปรียบ # 2 : เนื่องจาก OPTION # 2 สร้างตารางที่ไม่มีดัชนีที่ผู้ใช้กำหนดตารางควรโหลดเร็วกว่าถ้าทำตารางผ่าน OPTION # 1

2

นอกเหนือจากการตั้งค่าระดับการแยกธุรกรรมเป็น READ COMMITTED (หรือ READ UNCOMMITTED) คุณต้องตั้งค่ารูปแบบบันทึกไบนารี่เป็น MIXED หรือ ROW การจำลองแบบที่ใช้คำสั่งนี้จะล็อคคำสั่งประเภทนี้เพื่อให้แน่ใจว่าทุกอย่าง "ปลอดภัย" คุณยังสามารถตั้งค่าinnodb_locks_unsafe_for_binlog = 1 ได้ชั่วคราว แต่คุณสามารถจบลงด้วยทาสที่ซิงค์ไม่ได้

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

น่าเสียดายที่นี่ใช้งานไม่ได้ :(
clops

1
ผลลัพธ์ของ SHOW ENGINE INNODB STATUS เมื่อคำสั่ง CREATE TABLE กำลังทำงานอยู่?
Aaron Brown

1
นอกจากนี้ตรวจสอบให้แน่ใจว่าคุณกำลังใช้งาน READ COMMITTED ไม่ใช่ READ UNITMITTED คุณอาจพบข้อผิดพลาดนี้ที่ไม่ได้รับการแก้ไขจนกว่า 5.1.47 bugs.mysql.com/bug.php?id=48607
Aaron Brown

1
มันแปลกมาก มีกุญแจต่างประเทศหรือไม่? คุณสามารถโพสต์สถานะ INNODB ขณะที่พยายามอัพเดตแถวได้หรือไม่? คุณลองสิ่งนี้กับ MySQL เวอร์ชั่นใหม่กว่านี้ไหม? (ฉันเดาว่าคุณกำลังใช้ 5.1.41 เพราะมันมาพร้อมกับการกระจายของคุณหรือไม่)
Aaron Brown

1
คุณแน่ใจหรือว่าตารางผู้ใช้ของคุณคือ InnoDB? การอัพเดตไม่ปรากฏในเอาต์พุต SHOW ENGINE INNODB STATUS และในรายการกระบวนการมันจะปรากฏเป็นล็อคซึ่งโดยปกติแล้วเป็นผลมาจากตาราง MyISAM ฉันดีใจที่คำตอบของ @ RolandoMySQLDBA สามารถแก้ไขปัญหาของคุณได้ แต่ฉันคิดว่ามีบางอย่างเกิดขึ้นที่นี่
Aaron Brown
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.