สร้างดัชนีบนตารางการผลิต MySQL ขนาดใหญ่โดยไม่ต้องล็อกตาราง


106

ฉันต้องการสร้างดัชนีบนตาราง MySQL ~ 5M แถว มันเป็นตารางการผลิตและฉันกลัวว่าทุกอย่างจะสมบูรณ์แบบถ้าฉันเรียกใช้คำสั่ง CREATE INDEX ...

มีวิธีสร้างดัชนีโดยไม่ปิดกั้นการแทรกและเลือกหรือไม่?

แค่สงสัยว่าฉันยังไม่หยุดสร้างดัชนีและรีสตาร์ทระบบของฉัน!


1
ตรวจสอบให้แน่ใจว่า myisam_sort_buffer_size และ myisam_max_sort_file_size ของคุณมีขนาดใหญ่เพียงพอ
Jon Black

คำตอบ:


132

[2017] อัปเดต: MySQL 5.6 รองรับการอัปเดตดัชนีออนไลน์

https://dev.mysql.com/doc/refman/8.0/en/innodb-online-ddl-operations.html#online-ddl-index-syntax-notes

ใน MySQL 5.6 ขึ้นไปตารางยังคงพร้อมใช้งานสำหรับการอ่านและเขียนในขณะที่ดัชนีกำลังสร้างหรือลดลง คำสั่ง CREATE INDEX หรือ DROP INDEX จะเสร็จสิ้นหลังจากที่ธุรกรรมทั้งหมดที่เข้าถึงตารางเสร็จสมบูรณ์เท่านั้นดังนั้นสถานะเริ่มต้นของดัชนีจะแสดงถึงเนื้อหาล่าสุดของตาราง ก่อนหน้านี้การปรับเปลี่ยนตารางในขณะที่ดัชนีกำลังถูกสร้างหรือลดลงมักจะทำให้เกิดการชะงักงันที่ยกเลิกคำสั่ง INSERT, UPDATE หรือ DELETE บนตาราง

[2015] การอัปเดตตารางตัวบ่งชี้บล็อกเขียนใน MySQL 5.5

จากคำตอบด้านบน:

"หากคุณใช้เวอร์ชันที่มากกว่า 5.1 ดัชนีถูกสร้างขึ้นในขณะที่ฐานข้อมูลออนไลน์อยู่ดังนั้นไม่ต้องกังวลว่าคุณจะไม่ขัดขวางการใช้งานระบบการผลิต"

นี่คือ **** FALSE **** (อย่างน้อยสำหรับตาราง MyISAM / InnoDB ซึ่งเป็นสิ่งที่ 99.999% ของคนที่นั่นใช้ Clustered Edition แตกต่างกัน)

การดำเนินการ UPDATE บนตารางจะBLOCKในขณะที่กำลังสร้างดัชนี MySQL โง่จริงๆเกี่ยวกับเรื่องนี้ (และอีกสองสามอย่าง)

สคริปต์ทดสอบ:

(   
  for n in {1..50}; do
    #(time mysql -uroot -e 'select  * from website_development.users where id = 41225\G'>/dev/null) 2>&1 | grep real;
    (time mysql -uroot -e 'update website_development.users set bio="" where id = 41225\G'>/dev/null) 2>&1 | grep real;
  done
) | cat -n &
PID=$!
sleep 0.05
echo "Index Update - START"
mysql -uroot website_development -e 'alter table users add index ddopsonfu (last_name, email, first_name, confirmation_token, current_sign_in_ip);'
echo "Index Update - FINISH"
sleep 0.05
kill $PID
time mysql -uroot website_development -e 'drop index ddopsonfu on users;'

เซิร์ฟเวอร์ของฉัน (InnoDB):

Server version: 5.5.25a Source distribution

เอาต์พุต (สังเกตว่าบล็อกการดำเนินการที่ 6 สำหรับ ~ 400ms ใช้เวลาในการอัพเดตดัชนีให้เสร็จสิ้นอย่างไร):

 1  real    0m0.009s
 2  real    0m0.009s
 3  real    0m0.009s
 4  real    0m0.012s
 5  real    0m0.009s
Index Update - START
Index Update - FINISH
 6  real    0m0.388s
 7  real    0m0.009s
 8  real    0m0.009s
 9  real    0m0.009s
10  real    0m0.009s
11  real    0m0.009s

Vs อ่านการดำเนินการที่ไม่ปิดกั้น (สลับความคิดเห็นบรรทัดในสคริปต์):

 1  real    0m0.010s
 2  real    0m0.009s
 3  real    0m0.009s
 4  real    0m0.010s
 5  real    0m0.009s
Index Update - START
 6  real    0m0.010s
 7  real    0m0.010s
 8  real    0m0.011s
 9  real    0m0.010s
...
41  real    0m0.009s
42  real    0m0.010s
43  real    0m0.009s
Index Update - FINISH
44  real    0m0.012s
45  real    0m0.009s
46  real    0m0.009s
47  real    0m0.010s
48  real    0m0.009s

การอัปเดต Schema ของ MySQL โดยไม่ต้องหยุดทำงาน

ด้วยเหตุนี้มีเพียงวิธีเดียวที่ฉันรู้ในการอัปเดตสคีมา MySql และไม่ประสบปัญหาการหยุดทำงาน ปริญญาโทแบบวงกลม:

  • Master A มีฐานข้อมูล MySQL ของคุณทำงานอยู่
  • นำ Master B เข้ารับราชการและให้จำลองงานเขียนจาก Master A (B เป็นทาสของ A)
  • ทำการอัปเดตสคีมาบน Master B ซึ่งจะล้มเหลวในระหว่างการอัปเกรด
  • ให้อาจารย์ B จับได้ ไม่เปลี่ยนแปลง: การเปลี่ยนแปลงสคีมาของคุณต้องสามารถประมวลผลคำสั่งที่จำลองแบบจากสกีมาเวอร์ชันดาวน์ การเปลี่ยนแปลงการจัดทำดัชนีมีคุณสมบัติ การเพิ่มคอลัมน์อย่างง่ายมักจะมีคุณสมบัติ การลบคอลัมน์? อาจจะไม่.
  • แลกเปลี่ยนไคลเอนต์ทั้งหมดจาก Master A เป็น Master B อย่างแน่นอนหากคุณต้องการความปลอดภัย (เชื่อฉันเถอะคุณทำ) คุณควรตรวจสอบให้แน่ใจว่าการเขียนถึง A ครั้งสุดท้ายถูกจำลองเป็น B ก่อนB เขียนครั้งแรก หากคุณอนุญาตให้เขียนพร้อมกันถึงผู้เชี่ยวชาญ 2 คนขึ้นไป ... คุณจะเข้าใจการจำลองแบบ MySQL ในระดับ DEEP ได้ดีขึ้นหรือคุณกำลังมุ่งหน้าไปสู่โลกแห่งความเจ็บปวด ปวดมาก ชอบคุณมีคอลัมน์ที่เป็น AUTOINCREMENT หรือไม่ ??? คุณเมา (เว้นแต่ว่าคุณจะใช้เลขคู่กับตัวหลักหนึ่งตัวและอีกตัวหนึ่ง) อย่าเชื่อการจำลองแบบ MySQL ว่า "ทำในสิ่งที่ถูกต้อง" มันไม่ฉลาดและจะไม่ช่วยคุณ ปลอดภัยน้อยกว่าการคัดลอกบันทึกธุรกรรมไบนารีจากบรรทัดคำสั่งและเล่นซ้ำด้วยมือ ถึงกระนั้นการยกเลิกการเชื่อมต่อไคลเอนต์ทั้งหมดจากมาสเตอร์เก่าและพลิกไปยังมาสเตอร์ใหม่สามารถทำได้ภายในเวลาไม่กี่วินาทีเร็วกว่าการรอการอัปเกรดสคีมาหลายชั่วโมง
  • ตอนนี้อาจารย์ B คือนายคนใหม่ของคุณ คุณมีสคีมาใหม่ ชีวิตเป็นสิ่งที่ดี. ดื่มเบียร์ สิ่งที่เลวร้ายที่สุดจบลงแล้ว
  • ทำซ้ำขั้นตอนกับ Master A อัปเกรดสคีมาของเขาเพื่อให้เขากลายเป็นนายรองคนใหม่ของคุณพร้อมที่จะเข้ารับช่วงต่อในกรณีที่มาสเตอร์หลักของคุณ (ตอนนี้มาสเตอร์ B) สูญเสียพลังหรือเพิ่งขึ้นและตายกับคุณ

วิธีง่ายๆในการอัปเดตสคีมานี้ไม่ใช่ สามารถทำงานได้ในสภาพแวดล้อมการผลิตที่จริงจัง ใช่แล้ว. ได้โปรดได้โปรดหากมีวิธีที่ง่ายกว่าในการเพิ่มดัชนีลงในตาราง MySQL โดยไม่ต้องบล็อกการเขียนโปรดแจ้งให้เราทราบ

Googling นำฉันไปสู่บทความนี้ซึ่งอธิบายถึงเทคนิคที่คล้ายกัน ยิ่งไปกว่านั้นพวกเขาแนะนำให้ดื่มในจุดเดียวกันในขั้นตอนการดำเนินการ (โปรดทราบว่าฉันเขียนคำตอบก่อนอ่านบทความ)!

pt-online-schema-change ของ Percona

บทความฉันเชื่อมโยงดังกล่าวพูดคุยเกี่ยวกับเครื่องมือPT-ออนไลน์คีมาเปลี่ยนงานที่ดังต่อไปนี้:

  • สร้างตารางใหม่ด้วยโครงสร้างเดียวกันกับต้นฉบับ
  • อัปเดตสคีมาบนตารางใหม่
  • เพิ่มทริกเกอร์บนตารางต้นฉบับเพื่อให้การเปลี่ยนแปลงซิงค์กับสำเนา
  • คัดลอกแถวเป็นกลุ่มจากตารางเดิม
  • ย้ายตารางเดิมออกไปและแทนที่ด้วยตารางใหม่
  • วางโต๊ะเก่า

ฉันไม่เคยลองใช้เครื่องมือด้วยตัวเอง YMMV

RDS

ฉันกำลังใช้ MySQL ผ่านRDS ของ Amazon เป็นบริการที่ดีจริงๆที่รวบรวมและจัดการ MySQL ช่วยให้คุณเพิ่มแบบจำลองการอ่านใหม่ด้วยปุ่มเดียวและอัปเกรดฐานข้อมูลอย่างโปร่งใสใน SKU ของฮาร์ดแวร์ สะดวกจริงๆ คุณไม่สามารถเข้าถึงฐานข้อมูลได้อย่างยอดเยี่ยมดังนั้นคุณจึงไม่สามารถใช้การจำลองแบบโดยตรงได้ (นี่คือพรหรือคำสาป?) อย่างไรก็ตามคุณสามารถใช้Read Replica Promotionเพื่อทำการเปลี่ยนแปลงสคีมาของคุณบนทาสแบบอ่านอย่างเดียวจากนั้นเลื่อนระดับทาสนั้นให้กลายเป็นนายใหม่ของคุณ เคล็ดลับเดียวกับที่ฉันอธิบายไว้ข้างต้นเพียงแค่ดำเนินการได้ง่ายขึ้นมาก พวกเขายังไม่ช่วยคุณในการตัดต่อ คุณต้องกำหนดค่าใหม่และรีสตาร์ทแอปของคุณ


3
pt-online-schema-change ทำงานได้ดีแม้ในการจำลองแบบ master-slave ฉันเคยใช้มันเพื่อทำการโอนย้ายแบบสดบนตารางเรกคอร์ด 20M + ที่อ่านไม่ว่างบนฐานข้อมูลหลักในการผลิตของเราที่มีทาสการจำลอง 2 ตัวโดยไม่มีอาการสะอึกหรือหยุดทำงาน ต้องใช้เวลาพอสมควรในการเตรียมสคริปต์และฉันมักจะต้องสร้างไฟล์. sql ที่มีการเปลี่ยนแปลง SQL ดิบและไฟล์. sh เป็น wrapper เพื่อเรียกใช้ SQL เดียวกัน แต่อยู่ในรูปแบบแฟรกเมนต์ (ไม่มี ALTER TABLE) คุณสามารถรันคำสั่งได้หลายคำสั่งด้วย pt-online-schema-change โดยการรวมคำสั่งและคั่นด้วยลูกน้ำ
Alex Le

-1; ฉันไม่รู้เกี่ยวกับเวอร์ชันเก่า แต่ฉันรู้ว่าการสร้างดัชนีไม่ได้บล็อก DML พร้อมกันใน MySQL 5.6+ (ซึ่งมี RC อยู่ในขณะที่เขียนคำตอบนี้และซึ่งได้รับการเผยแพร่อย่างเป็นทางการเมื่อคำตอบนี้คงอยู่ แก้ไขในเดือนพฤษภาคม 2013) เนื่องจากฉันได้ใช้สิ่งนี้ในการเรียกใช้การสร้างดัชนีหลายชั่วโมงบนตารางการผลิตในขณะที่ยังยอมรับการแทรก และในขณะที่คุณอาจพูดถูกเกี่ยวกับการสร้างดัชนีที่บล็อก DML ใน 5.5 และต่ำกว่า แต่ความล่าช้าในวินาทีย่อยที่แสดงที่นี่ก็ไม่น่าเชื่ออย่างสิ้นเชิง
Mark Amery

@MarkAmery - พฤติกรรมการบล็อกคือพฤติกรรมการบล็อกและ 400ms เป็นสิ่งที่ไม่สิ้นสุด MySQL 5.5 บล็อกสำหรับการอัปเดตดัชนี สร้างฐานข้อมูลทดสอบที่ใหญ่ขึ้นและจะบล็อกเป็นวินาทีชั่วโมงหรือวัน ฉันเขียนโพสต์นี้ก่อน MySQL 5.6 จะมีการอัปเดตสคีมาออนไลน์ดังนั้นเนื้อหาต้นฉบับของฉันจึงไม่สะท้อนถึงข้อเท็จจริงนั้น ฉันได้อัปเดตโพสต์เพื่อแสดงข้อมูลที่มีอยู่ใหม่
Dave Dopson

@DaveDopson คุณแน่ใจ 100% หรือไม่ว่าเฉพาะการอัปเดตเท่านั้นที่ถูกบล็อก?
toto_tico

นั่นเป็นกรณีของเวอร์ชันที่ฉันทดสอบ
Dave Dopson

67

ตามที่บล็อกโพสต์นี้มีเค้าโครง InnoDBALTER TABLEกลไกได้รับการออกแบบใหม่ทั้งหมดสำหรับ MySQL 5.6

(สำหรับภาพรวมเฉพาะของหัวข้อนี้เอกสาร MySQLสามารถให้ความคุ้มค่าในการอ่านในช่วงบ่าย)

ในการเพิ่มดัชนีลงในตารางโดยไม่มีการล็อกที่เกิดจากUPDATE/ INSERTสามารถใช้รูปแบบคำสั่งต่อไปนี้:

ALTER TABLE my_table ADD INDEX my_table__idx (my_column), ALGORITHM=INPLACE, LOCK=NONE;


16

การอัปเดต MySQL 5.6 (กุมภาพันธ์ 2013): ขณะนี้คุณสามารถดำเนินการอ่านและเขียนได้ในขณะที่สร้างดัชนีแม้จะมีตาราง InnoDB - http://dev.mysql.com/doc/refman/5.6/en/innodb-create-index -overview.html

ใน MySQL 5.6 ขึ้นไปตารางยังคงพร้อมใช้งานสำหรับการอ่านและเขียนในขณะที่ดัชนีกำลังสร้างหรือลดลง คำสั่ง CREATE INDEX หรือ DROP INDEX จะเสร็จสิ้นหลังจากที่ธุรกรรมทั้งหมดที่เข้าถึงตารางเสร็จสมบูรณ์เท่านั้นดังนั้นสถานะเริ่มต้นของดัชนีจะแสดงถึงเนื้อหาล่าสุดของตาราง ก่อนหน้านี้การปรับเปลี่ยนตารางในขณะที่ดัชนีกำลังถูกสร้างหรือลดลงมักจะทำให้เกิดการชะงักงันที่ยกเลิกคำสั่ง INSERT, UPDATE หรือ DELETE บนตาราง

และ:

ใน MySQL 5.6 คุณลักษณะนี้มีลักษณะทั่วไปมากขึ้น: คุณสามารถอ่านและเขียนลงในตารางได้ในขณะที่สร้างดัชนีและสามารถดำเนินการ ALTER TABLE ได้หลายประเภทโดยไม่ต้องคัดลอกตารางโดยไม่บล็อกการดำเนินการ DML หรือทั้งสองอย่าง ดังนั้นใน MySQL 5.6 ขึ้นไปโดยทั่วไปเราจะอ้างถึงคุณสมบัติชุดนี้ว่า DDL ออนไลน์แทนที่จะสร้างดัชนีอย่างรวดเร็ว

จากhttp://dev.mysql.com/doc/refman/5.6/en/glossary.html#glos_fast_index_creation


แล้วการวิเคราะห์ของ Dave จะอธิบายได้อย่างไร?
Nikhil Sahu

1
@NikhilSahu Dave ไม่ได้ทดสอบบน MySQL 5.6 อย่างชัดเจน แต่เป็นเวอร์ชันเก่าบางรุ่น โปรดทราบว่า 5.6 ยังไม่ได้รับการเผยแพร่ในจุดที่ Dave โพสต์การแก้ไขครั้งแรกของคำตอบของเขา
Mark Amery

+1. การวิเคราะห์ของฉันใช้ MySQL 5.5 (ล่าสุดที่มีใน 2013) ฉันกำลังอัปเดตคำตอบเพื่อแสดงถึงความสามารถใหม่ใน MySQL 5.6
Dave Dopson

3

pt-online-schema-change เป็นวิธีที่จะไปหากคุณต้องการให้แน่ใจว่าการย้ายข้อมูลจะไม่ทำให้ไซต์ล่ม

ดังที่ฉันเขียนไว้ในความคิดเห็นข้างต้นฉันมีประสบการณ์มากมายเกี่ยวกับการเปลี่ยนแปลง pt-online-schema-change ในการผลิต เรามีตารางหลักของเรกคอร์ด 20M + และมาสเตอร์ -> 2 ทาสการจำลองแบบอ่านอย่างเดียว ฉันได้ทำการโยกย้ายอย่างน้อยหลายสิบครั้งด้วย pt-online-schema-change ตั้งแต่การเพิ่มคอลัมน์ใหม่การเปลี่ยนชุดอักขระไปจนถึงการเพิ่มดัชนีต่างๆ เราให้บริการปริมาณการใช้งานจำนวนมากในช่วงเวลาอพยพเช่นกันและเราไม่ได้มีอาการสะอึกใด ๆ แน่นอนว่าคุณต้องทดสอบสคริปต์ทั้งหมดอย่างละเอียดก่อนที่จะดำเนินการผลิต

ฉันพยายามรวมการเปลี่ยนแปลงเป็น 1 สคริปต์เพื่อให้ pt-online-schema-change ต้องคัดลอกข้อมูลเพียงครั้งเดียว และระมัดระวังในการเปลี่ยนชื่อคอลัมน์เนื่องจากข้อมูลของคุณจะสูญเสียไป อย่างไรก็ตามควรเพิ่มดัชนี


ฉันไม่เห็นด้วยกับคำแนะนำที่ไม่มีเงื่อนไขของpt-online-schema-changeคุณ มันยอดเยี่ยม แต่ก็เกินความสามารถสำหรับหลาย ๆ สถานการณ์ที่ความสามารถ DDL ออนไลน์ของ MySQL 5.6 + ทำงานได้ดีอยู่แล้ว นอกจากนี้ยังมีข้อ จำกัด (เช่นการไม่เล่นกับทริกเกอร์อย่างดี) และเพิ่มจำนวนการเขียนที่จำเป็นต่อการแทรกลงในตารางเดิมเป็นสองเท่าในขณะที่กำลังดำเนินการเปลี่ยนแปลงสคีมา มันจะเก็บภาษีดิสก์ของคุณอย่างมากมากกว่าการเปลี่ยนแปลงสคีมาออนไลน์ทั่วไปดังนั้นจึงมีความเป็นไปได้ที่จะ "ลดไซต์ของคุณ" ในสถานการณ์ที่เพียงแค่เรียกใช้สคีมาเปลี่ยนวิธีง่ายๆก็จะได้ผลดี
Mark Amery

ฉันเขียนขึ้นจากประสบการณ์จริงของฉันเกี่ยวกับ pt-online-schema-change ในเวลานั้นดังนั้นฉันจึงไม่แน่ใจว่าทำไมคุณถึงเรียกคำแนะนำของฉันว่า "ไม่มีคุณสมบัติ" เรามีผู้เยี่ยมชมไซต์อย่างน้อย 1,000+ คนในช่วงเวลาใดก็ตามที่ฉันดำเนินการเปลี่ยนแปลงสคีมาและแน่นอนว่าดิสก์ IO กำลังเก็บภาษี แต่ไซต์ของเราไม่ได้ลดลง การแคชที่ดีก็ช่วยได้เช่นกัน ฉันไม่ได้ใช้ MySQL 5.6+ ออนไลน์ DDL แต่จากประสบการณ์ของฉัน pt-online-schema-change ทำงานได้ดีในกรณีของเรา
Alex Le

1
@AlexYe Yikes ฉันหมายถึง "ไม่มีเงื่อนไข" ในความหมายของ "โดยไม่มีการจอง" มากกว่าความหมายของ "ส่งโดยคนที่ไม่มีคุณสมบัติในการแสดงความคิดเห็น" - การตีความครั้งหลังไม่เกิดขึ้นกับฉันจนกว่าฉันจะเห็นความคิดเห็นของคุณและแน่นอนว่าไม่มี สิ่งที่ฉันตั้งใจ! กล่าวคือฉันกำลังบอกว่าแม้ว่าpt-online-schema-changeจะเป็นเครื่องมือที่มีประโยชน์ แต่ก็มีหลายสถานการณ์ที่ DDL ออนไลน์ทั่วไปนั้นดีพอ ๆ กันและมีเพียงไม่กี่แห่งที่ดีกว่าดังนั้นคำแนะนำใด ๆ ควรระบุไว้อย่างรอบคอบมากกว่าสากล
Mark Amery
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.