ฐานข้อมูล MySQL InnoDB 'หยุด' ที่เลือก


10

ฉันพยายามแก้ไขการกำหนดค่า MySQL บนเซิร์ฟเวอร์ของเรา ข้อมูลเฉพาะของแอปของเราคือข้อมูลจำนวนมากถูกจัดเก็บไว้ในตารางเดียว (ปัจจุบันมีมากกว่า 300 ล้านแถว) ตารางนี้ใช้สำหรับแทรกบ่อยครั้ง (จะปรากฏตลอดเวลา)

เมื่อฉันเรียกใช้แบบสอบถามแบบใช้เลือกข้อมูลบนตารางที่ใช้เวลานานกว่าสองสามวินาทีการแทรกทั้งหมด (กระทำอย่างแม่นยำ) กำลังรอการเข้าถึงตารางและทำให้แอปของเราไม่ตอบสนอง

เท่าที่ฉันรู้ InnoDB ไม่ได้ล็อคใด ๆ บนโต๊ะเมื่อเลือกกำลังทำงานอยู่ เหตุใดตารางการเลือกบล็อกจึงเป็นเช่นนั้น

ฉันพยายามหาเหตุผลด้วย innotop แต่ฉันไม่แน่ใจว่าจะตีความมันออกมาได้อย่างไรและจะค้นหาที่ไหน บอกสิ่งที่คุณต้องการและฉันจะโพสต์ที่นี่

+-----+---------+-----------+--------+---------+------+----------------+-----------------------------------------------------------------------------------------------------------------------------------+
| Id  | User    | Host      | db     | Command | Time | State          | Info                                                                                                                              |
+-----+---------+-----------+--------+---------+------+----------------+-----------------------------------------------------------------------------------------------------------------------------------+
|   1 | root    | localhost | dbname | Query   |   29 | NULL           | COMMIT                                                                                                                            | 
|   2 | root    | localhost | dbname | Query   |   30 | NULL           | COMMIT                                                                                                                            | 
|   4 | root    | localhost | dbname | Query   |   29 | NULL           | COMMIT                                                                                                                            | 
|   5 | root    | localhost | dbname | Query   |   29 | NULL           | COMMIT                                                                                                                            | 
|   6 | root    | localhost | dbname | Query   |   25 | NULL           | COMMIT                                                                                                                            | 
|   7 | root    | localhost | dbname | Query   |    0 | NULL           | show full processlist                                                                                                             | 
|  13 | user    | localhost | dbname | Query   |   25 | NULL           | COMMIT                                                                                                                            | 
|  38 | user    | localhost | dbname | Sleep   |    0 |                | NULL                                                                                                                              | 
|  39 | user    | localhost | dbname | Sleep   | 9017 |                | NULL                                                                                                                              | 
|  40 | user    | localhost | dbname | Query   |   33 | Sorting result | SELECT * FROM `large_table` WHERE (`large_table`.`hotspot_id` = 3000064)  ORDER BY discovered_at LIMIT 799000, 1000 | 
|  60 | user    | localhost | dbname | Sleep   | 1033 |                | NULL                                                                                                                              | 
|  83 | root    | localhost | dbname | Sleep   | 3728 |                | NULL                                                                                                                              | 
| 112 | root    | localhost | NULL   | Sleep   |    6 |                | NULL                                                                                                                              | 
+-----+---------+-----------+--------+---------+------+----------------+-----------------------------------------------------------------------------------------------------------------------------------+


=====================================
110824 12:24:24 INNODB MONITOR OUTPUT
=====================================
Per second averages calculated from the last 19 seconds
----------
SEMAPHORES
----------
OS WAIT ARRAY INFO: reservation count 1521117, signal count 1471216
Mutex spin waits 0, rounds 20647617, OS waits 239914
RW-shared spins 2119697, OS waits 1037149; RW-excl spins 505734, OS waits 218177
------------
TRANSACTIONS
------------
Trx id counter 0 412917332
Purge done for trx's n:o < 0 412917135 undo n:o < 0 0
History list length 48
Total number of lock structs in row lock hash table 5
LIST OF TRANSACTIONS FOR EACH SESSION:
---TRANSACTION 0 0, not started, process no 28363, OS thread id 1092766032
MySQL thread id 83, query id 3249941 localhost root
---TRANSACTION 0 412901582, not started, process no 28363, OS thread id 1144449360
MySQL thread id 60, query id 3677008 localhost user
---TRANSACTION 0 412917189, not started, process no 28363, OS thread id 1144314192
MySQL thread id 43, query id 3905773 localhost root
---TRANSACTION 0 412534255, not started, process no 28363, OS thread id 1092630864
MySQL thread id 39, query id 14279 localhost user
---TRANSACTION 0 412917331, not started, process no 28363, OS thread id 1144179024
MySQL thread id 38, query id 3908045 localhost user
---TRANSACTION 0 412917201, not started, process no 28363, OS thread id 1092495696
MySQL thread id 13, query id 3908257 localhost user
---TRANSACTION 0 412538821, not started, process no 28363, OS thread id 1092360528
MySQL thread id 7, query id 3908258 localhost root
show engine innodb status
---TRANSACTION 0 412917330, ACTIVE 6 sec, process no 28363, OS thread id 1144043856
2 lock struct(s), heap size 368, undo log entries 1
MySQL thread id 2, query id 3907373 localhost root
COMMIT
Trx read view will not see trx with id >= 0 412917331, sees < 0 412917131
---TRANSACTION 0 412917328, ACTIVE 6 sec, process no 28363, OS thread id 1092225360
2 lock struct(s), heap size 368, undo log entries 1
MySQL thread id 6, query id 3907345 localhost root
COMMIT
Trx read view will not see trx with id >= 0 412917329, sees < 0 412917131
---TRANSACTION 0 412917326, ACTIVE 6 sec, process no 28363, OS thread id 1091955024
2 lock struct(s), heap size 368, undo log entries 1
MySQL thread id 4, query id 3907335 localhost root
COMMIT
Trx read view will not see trx with id >= 0 412917327, sees < 0 412917131
---TRANSACTION 0 412917324, ACTIVE 6 sec, process no 28363, OS thread id 1092090192
2 lock struct(s), heap size 368, undo log entries 1
MySQL thread id 5, query id 3907328 localhost root
COMMIT
Trx read view will not see trx with id >= 0 412917325, sees < 0 412917131
---TRANSACTION 0 412917321, ACTIVE (PREPARED) 7 sec, process no 28363, OS thread id 1143908688 preparing
2 lock struct(s), heap size 368, undo log entries 1
MySQL thread id 1, query id 3907125 localhost root
COMMIT
Trx read view will not see trx with id >= 0 412917322, sees < 0 412917131
---TRANSACTION 0 412917131, ACTIVE 20 sec, process no 28363, OS thread id 1074075984, thread declared inside InnoDB 111
mysql tables in use 1, locked 0
MySQL thread id 40, query id 3904958 localhost user Sorting result
SELECT * FROM `large_table` WHERE (`large_table`.`hotspot_id` = 3000064)  ORDER BY discovered_at LIMIT 848000, 1000
Trx read view will not see trx with id >= 0 412917132, sees < 0 412917132
--------
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: 1; buffer pool: 0
3510225 OS file reads, 284998 OS file writes, 202897 OS fsyncs
1.05 reads/s, 21299 avg bytes/read, 8.10 writes/s, 7.58 fsyncs/s
-------------------------------------
INSERT BUFFER AND ADAPTIVE HASH INDEX
-------------------------------------
Ibuf: size 275, free list len 13392, seg size 13668,
489950 inserts, 491830 merged recs, 10986 merges
Hash table size 8850487, used cells 8127172, node heap has 32697 buffer(s)
71914.53 hash searches/s, 8701.91 non-hash searches/s
---
LOG
---
Log sequence number 157 3331524445
Log flushed up to   157 3331521939
Last checkpoint at  157 3326072846
1 pending log writes, 0 pending chkp writes
199025 log i/o's done, 7.53 log i/o's/second
----------------------
BUFFER POOL AND MEMORY
----------------------
Total memory allocated 4788954432; in additional pool allocated 1048576
Buffer pool size   262144
Free buffers       0
Database pages     229447
Modified db pages  1439
Pending reads 0
Pending writes: LRU 0, flush list 0, single page 0
Pages read 7453325, created 14887, written 118658
1.37 reads/s, 0.11 creates/s, 0.53 writes/s
Buffer pool hit rate 1000 / 1000
--------------
ROW OPERATIONS
--------------
1 queries inside InnoDB, 0 queries in queue
7 read views open inside InnoDB
Main thread process no. 28363, id 1091684688, state: flushing log
Number of rows inserted 1093064, updated 249134, deleted 1405, read 1115880534
7.89 inserts/s, 2.47 updates/s, 0.05 deletes/s, 80953.21 reads/s
----------------------------
END OF INNODB MONITOR OUTPUT
============================

แก้ไข:

ขอขอบคุณที่ชี้แจงเรื่องนี้

ตอนนี้ฉันต้องแยกคำถามออกเป็นสองกรณี

  1. เป็นเรื่องปกติหรือไม่ที่การล็อคตารางเดี่ยวนี้ทำให้แอปทั้งหมดของฉัน 'หยุด' DB ไม่ควรตอบสนองต่อคิวรีไปยังตารางอื่น ๆ หรือไม่ อาจตั้งค่าบัฟเฟอร์บางส่วนต่ำเกินไปหรือไม่

  2. การสลับตารางนี้เป็น MyISAM จะช่วยได้หรือไม่ ฉันไม่ต้องการธุรกรรมในตารางนี้เลย จะไม่มีการล็อคอื่น ๆ ในสถานการณ์เช่นนั้น (เลือกแบบยาว + แทรกเร็วจำนวนมาก)?

EDIT2:

นั่นคือลักษณะของการแทรกข้อความค้นหา:

INSERT INTO `large_table` (`device_address`, `hotspot_id`, `minute`, `created_at`, `updated_at`, `discovered_with_hci`, `hour`, `rssi`, `day`, `device_class`, `discovered_at`) VALUES('10:40:03:90:10:40', 3000008, 1, '2011-08-22 05:01:08', '2011-08-22 05:01:08', -1, 5, -79, '2011-08-22 05:01:01', '0', '2011-08-22 05:01:01')

นั่นคือดัชนีที่นิยามไว้:

+-------------+------------+----------------------------------------------+--------------+---------------------+-----------+-------------+----------+--------+------+------------+---------+
| Table       | Non_unique | Key_name                                     | Seq_in_index | Column_name         | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+-------------+------------+----------------------------------------------+--------------+---------------------+-----------+-------------+----------+--------+------+------------+---------+
| large_table |          0 | PRIMARY                                      |            1 | id                  | A         |    92396334 |     NULL | NULL   |      | BTREE      |         | 
| large_table |          1 | index_large_table_on_discovered_with_hci     |            1 | discovered_with_hci | A         |          18 |     NULL | NULL   | YES  | BTREE      |         | 
| large_table |          1 | index_large_table_on_hotspot_id              |            1 | hotspot_id          | A         |          18 |     NULL | NULL   | YES  | BTREE      |         | 
| large_table |          1 | index_large_table_on_day_and_hour_and_minute |            1 | day                 | A         |          18 |     NULL | NULL   | YES  | BTREE      |         | 
| large_table |          1 | index_large_table_on_day_and_hour_and_minute |            2 | hour                | A         |          18 |     NULL | NULL   | YES  | BTREE      |         | 
| large_table |          1 | index_large_table_on_day_and_hour_and_minute |            3 | minute              | A         |      537187 |     NULL | NULL   | YES  | BTREE      |         | 
| large_table |          1 | index_large_table_on_created_at              |            1 | created_at          | A         |     8399666 |     NULL | NULL   | YES  | BTREE      |         | 
| large_table |          1 | index_large_table_on_rssi                    |            1 | rssi                | A         |          18 |     NULL | NULL   | YES  | BTREE      |         | 
+-------------+------------+----------------------------------------------+--------------+---------------------+-----------+-------------+----------+--------+------+------------+---------+

แก้ไข 3:

เหตุใดในระหว่างการค้นหาทั้งหมดใบสมัครของฉันจึงไม่ตอบสนอง ไม่ควรส่งผลกระทบต่อเฉพาะ 'large_table' หรือไม่

อาจมีบางอย่างผิดปกติกับการกำหนดค่า mysql ของฉันหรือไม่ เซิร์ฟเวอร์เป็น Xeon 2GHz 4 คอร์ที่มี 16GB RAM มันรันแอพ MySQL + Rails

พารามิเตอร์การกำหนดค่าของฉัน:

skip-external-locking
key_buffer              = 64M
max_allowed_packet      = 16M
thread_stack            = 128K
thread_cache_size       = 8
query_cache_size        = 32M
tmp_table_size          = 64M
max_heap_table_size     = 64M
table_cache             = 256
read_rnd_buffer_size    = 512K
sort_buffer_size        = 2M

myisam-recover          = BACKUP
max_connections         = 200

query_cache_limit       = 1M

long_query_time = 200

max_binlog_size         = 100M

innodb_buffer_pool_size = 4G
safe-updates
max_join_size=100000000

สคริปต์ Mysqltuner แนะนำเท่านั้น:

long_query_time (<= 10)
innodb_buffer_pool_size (>= 62G)

show engine innodb status;โปรดผนวกการส่งออกของ
quanta

ใน innotop คุณสามารถกด L เพื่อดูมุมมองได้ในล็อค แอปของคุณสร้างการเชื่อมต่อได้อย่างไร JDBC? คุณกำลังใช้ระดับเริ่มต้นธุรกรรมการโต้ตอบอะไร
HTTP500

มันเป็นแอพพลิเคชั่น RoR ดังนั้นฉันเดาว่ามันเป็นค่าเริ่มต้นสำหรับ MySQL (ฉันสามารถตรวจสอบได้ด้วยแบบสอบถาม SQL) innotop ไม่แสดงการล็อคใด ๆ ในขณะที่ตัวเลือกนี้ทำงาน
kaczor1984

@ kaczor1984 คุณสามารถตรวจสอบระดับการแยกเริ่มต้นได้โดยทำ a: แสดงตัวแปรเช่น 'tx_isolation'; สอบถาม ค่าเริ่มต้นคือ REPEATABLE READ โปรดทราบว่า MVCC ทำงานได้เฉพาะกับ REPEATABLE READ และ READ COMMITTED เท่านั้น ไม่แน่ใจว่าโซลูชันของคุณคืออะไร แต่คำตอบ RolandoMySQLDBAs นั้นเป็นข้อมูล
HTTP500

อัปเดตคำตอบของฉันด้วยการวิเคราะห์ข้อความค้นหาที่ Process ID 40
RolandoMySQLDBA

คำตอบ:


15

โปรดดูรายการกระบวนการอย่างละเอียดและ 'แสดงสถานะเครื่องมือ Innodb' คุณเห็นอะไร ???

รหัสกระบวนการ 1,2,4,5,6,13 กำลังพยายามเรียกใช้ COMMIT

ใครเป็นผู้ถือครองทุกสิ่งทุกอย่าง ??? ประมวลผล ID 40 กำลังเรียกใช้แบบสอบถามกับ large_table

ID กระบวนการ 40 ทำงานเป็นเวลา 33 วินาที รหัสกระบวนการ 1,2,4,5,6,13 ทำงานน้อยกว่า 33 วินาที ID กระบวนการ 40 กำลังประมวลผลบางอย่าง อะไรกันบ้าง ???

แรกของทุกแบบสอบถามจะตำบน large_table ของดัชนีคลัสเตอร์ผ่านMVCC

ภายใน ID กระบวนการ 1,2,4,5,6,13 คือแถวที่มีข้อมูล MVCC ปกป้องการแยกธุรกรรม ประมวลผล ID 40 มีแบบสอบถามที่เดินผ่านแถวของข้อมูล หากมีดัชนีอยู่ในเขตฮอตสปอตหมายเลขที่คีย์ + คีย์ไปยังแถวที่เกิดขึ้นจริงจากดัชนีคลัสเตอร์จะต้องดำเนินการล็อคภายใน (หมายเหตุ: จากการออกแบบดัชนีที่ไม่ซ้ำกันทั้งหมดใน InnoDB จะมีทั้งคีย์ของคุณ (คอลัมน์ที่คุณต้องการให้ดัชนี) + คีย์ดัชนีคลัสเตอร์ สถานการณ์ที่ไม่เหมือนใครนี้ก็คือ Unstoppable Force ตรงกับวัตถุ

ในสาระสำคัญ COMMIT ต้องรอจนกว่าจะปลอดภัยที่จะใช้การเปลี่ยนแปลงกับ large_table สถานการณ์ของคุณไม่ซ้ำใครไม่ใช่ครั้งเดียวไม่ใช่ปรากฏการณ์ที่หายาก

ฉันตอบคำถามสามข้อเช่นนี้ใน DBA StackExchange คำถามถูกส่งโดยบุคคลเดียวกันที่เกี่ยวข้องกับปัญหาเดียวกัน คำตอบของฉันไม่ใช่วิธีแก้ปัญหา แต่ช่วยให้ผู้ส่งคำถามมาถึงข้อสรุปของเขาเองเกี่ยวกับวิธีจัดการกับสถานการณ์ของเขา

นอกจากนี้คำตอบเหล่านั้นฉันตอบคำถามของคนอื่นเกี่ยวกับการหยุดชะงักใน InnoDB เกี่ยวกับการเลือกด้วย

ฉันหวังว่าโพสต์ที่ผ่านมาของฉันในเรื่องนี้จะช่วยชี้แจงสิ่งที่เกิดขึ้นกับคุณ

อัพเดท 2011-08-25 08:10 EDT

นี่คือแบบสอบถามจากกระบวนการ ID 40

SELECT * FROM `large_table`
WHERE (`large_table`.`hotspot_id` = 3000064)
ORDER BY discovered_at LIMIT 799000, 1000;

สองข้อสังเกต:

  • คุณกำลังทำ 'เลือก *' คุณต้องการดึงข้อมูลทุกคอลัมน์หรือไม่ หากคุณต้องการเฉพาะคอลัมน์ที่เฉพาะเจาะจงคุณควรติดป้ายกำกับเหล่านั้นเนื่องจากตาราง temp ของ 1,000 แถวอาจใหญ่กว่าที่คุณต้องการจริงๆ

  • ส่วนคำสั่ง WHERE และ ORDER BY จะแจกประเด็นด้านประสิทธิภาพหรือออกแบบโต๊ะให้เปล่งปลั่ง คุณต้องสร้างกลไกที่จะเพิ่มความเร็วในการรวบรวมคีย์ก่อนรวบรวมข้อมูล

จากการสังเกตการณ์ทั้งสองนี้คุณต้องทำการเปลี่ยนแปลงที่สำคัญสองอย่าง:

MAJOR CHANGE # 1: สร้างการสืบค้นใหม่

ออกแบบแบบสอบถามใหม่เพื่อให้

  1. รวบรวมกุญแจจากดัชนี
  2. มีเพียง 1,000 คนเท่านั้นที่จะถูกรวบรวม
  3. เข้าร่วมกลับไปที่ตารางหลัก

นี่คือแบบสอบถามใหม่ที่ทำสามสิ่งนี้

SELECT large_table.* FROM
large_table INNER JOIN
(
    SELECT hotspot_id,discovered_at
    FROM large_table
    WHERE hotspot_id = 3000064
    ORDER BY discovered_at
    LIMIT 799000,1000
) large_table_keys
USING (hotspot_id,discovered_at);

เคียวรี่ย่อย large_table_keys รวบรวม 1,000 คีย์ที่คุณต้องการ ผลลัพธ์จากแบบสอบถามย่อยนั้นจะเข้าร่วมภายในเพื่อ large_table จนถึงตอนนี้คีย์จะถูกดึงข้อมูลแทนทั้งแถว ยังคงมีจำนวน 799,000 แถวเพื่ออ่าน มีวิธีที่ดีกว่าในการรับกุญแจเหล่านั้นซึ่งทำให้เรา ...

MAJOR CHANGE # 2: สร้างดัชนีที่รองรับการ Refactored Query

เนื่องจากแบบสอบถามที่ปรับโครงสร้างใหม่นั้นมีเพียงแบบสอบถามย่อยเดียวคุณจึงต้องสร้างดัชนีหนึ่งดัชนี นี่คือดัชนี:

ALTER TABLE large_table ADD INDEX hotspot_discovered_ndx (hotspot_id,discovered_at);

ทำไมดัชนีนี้โดยเฉพาะ? ดูคำสั่ง WHERE hotspot_id เป็นค่าคงที่ สิ่งนี้ทำให้ฮอตสปอตทั้งหมดสร้างรายการตามลำดับในดัชนี ตอนนี้ดูข้อ ORDER BY คอลัมน์ Discover_at อาจเป็นฟิลด์ DATETIME หรือ TIMESTAMP

ลำดับธรรมชาติที่นำเสนอในดัชนีมีดังนี้:

  • ดัชนีมีรายการของ hostpot_ids
  • แต่ละ hotspot_id มีรายการสั่งซื้อของฟิลด์ Discover_at

การจัดทำดัชนีนี้ยังช่วยลดการเรียงลำดับตารางชั่วคราวภายใน

โปรดใส่การเปลี่ยนแปลงสำคัญสองประการนี้เข้าด้วยกันและคุณจะเห็นความแตกต่างในเวลาทำงาน

ให้มันลอง !!!

อัพเดท 2011-08-25 08:15 EDT

ฉันดูดัชนีของคุณ คุณยังต้องสร้างดัชนีที่ฉันแนะนำ


ขอบคุณสำหรับคำอธิบายที่มากว่ามันทำงานอย่างไร ฉันเกรงว่าฉันจะไม่สามารถรู้ได้ว่าจะหลีกเลี่ยงสถานการณ์เช่นนั้นได้อย่างไร ส่วนแทรกต้องแก้ไขดัชนีและเลือกต้องใช้ดัชนีบน hotspot_id และ discover_at ฉันจะดีใจถ้าคุณยังสามารถ 'เปลี่ยนความคิด' เป็น MyISAM ได้
kaczor1984

ที่จริงแล้วการใช้ MyISAM อาจทำให้สิ่งต่าง ๆ แย่ลงเพราะแต่ละ INSERT, UPDATE และ DELETE ใน MyISAM จะกระตุ้นการล็อกตารางเต็มรูปแบบ แม้ว่าคุณจะใช้ LOW_PRIORITY INSERT หรือ INSERT ล่าช้าการล็อกเต็มตารางจะยังคงเกิดขึ้น คุณควรสำรวจแบบสอบถามด้วยตัวเองเพราะไม่ว่าจะเป็นเอ็นจิ้นการจัดเก็บข้อมูลใดคุณสามารถปรับแต่งคำถามต่างๆ อย่างน้อยที่สุดอาจต้องใช้อัลกอริทึมใหม่ทั้งหมด ฉันจะดูคำถามในสองสามนาที ...
RolandoMySQLDBA

ฉันได้อัปเดตการโพสต์ครั้งแรกของฉันเพื่อให้คุณสามารถดูการสืบค้นและดัชนีในตารางนี้
kaczor1984

อัปเดตคำตอบของฉันด้วยการวิเคราะห์ข้อความค้นหาที่ Process ID 40
RolandoMySQLDBA

4
คุณเป็นวีรบุรุษในหมู่มนุษย์สำหรับคำตอบ mysql ที่ยาวนานของคุณ
Mike

3

แก้ไข!

ปัญหาหลักคือ query_cache http://bugs.mysql.com/bug.php?id=21074

หลังจากปิดการใช้งานมัน 'ค้าง' หายไป


และขอขอบคุณ @RolandoMySQLDBA ที่ยอดเยี่ยมสำหรับคำแนะนำในการเพิ่มประสิทธิภาพการสืบค้นและดัชนีของฉัน
kaczor1984
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.