[2017] Cập nhật: MySQL 5.6 có hỗ trợ cập nhật chỉ mục trực tuyến
https://dev.mysql.com/doc/refman/8.0/en/innodb-online-ddl-operations.html#online-ddl-index-syntax-notes
Trong MySQL 5.6 trở lên, bảng vẫn có sẵn cho các hoạt động đọc và ghi trong khi chỉ mục đang được tạo hoặc xóa. Câu lệnh CREATE INDEX hoặc DROP INDEX chỉ kết thúc sau khi tất cả các giao dịch đang truy cập bảng được hoàn tất, để trạng thái ban đầu của chỉ mục phản ánh nội dung gần đây nhất của bảng. Trước đây, việc sửa đổi bảng trong khi một chỉ mục đang được tạo hoặc bị loại bỏ thường dẫn đến bế tắc hủy bỏ câu lệnh INSERT, UPDATE hoặc DELETE trên bảng.
[2015] Cập nhật các khối chỉ báo bảng ghi trong MySQL 5.5
Từ câu trả lời trên:
"Nếu bạn đang sử dụng phiên bản lớn hơn 5.1 chỉ số được tạo trong khi cơ sở dữ liệu trực tuyến. Vì vậy, đừng lo lắng, bạn sẽ không làm gián đoạn việc sử dụng hệ thống sản xuất."
Đây là **** FALSE **** (ít nhất là đối với các bảng MyISAM / InnoDB, đó là thứ mà 99,999% người dùng ngoài kia sử dụng. Clustered Edition thì khác.)
Thực hiện các thao tác CẬP NHẬT trên bảng sẽ CHẶN trong khi chỉ mục đang được tạo. MySQL thực sự, thực sự ngu ngốc về điều này (và một số thứ khác).
Tập lệnh thử nghiệm:
(
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;'
Máy chủ của tôi (InnoDB):
Server version: 5.5.25a Source distribution
Đầu ra (lưu ý cách khối hoạt động thứ 6 trong ~ 400ms cần để hoàn thành cập nhật chỉ mục):
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 các thao tác đọc không chặn (hoán đổi chú thích dòng trong tập lệnh):
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
Cập nhật Lược đồ của MySQL mà không có thời gian chết
Do đó, chỉ có một phương pháp mà tôi biết để cập nhật lược đồ MySql và không bị ngừng hoạt động. Các bậc thầy về vòng tròn:
- Master A có cơ sở dữ liệu MySQL của bạn đang chạy trên đó
- Đưa Master B vào hoạt động và để nó sao chép các ghi từ Master A (B là nô lệ của A)
- Thực hiện cập nhật giản đồ trên Master B. Nó sẽ bị trễ trong quá trình nâng cấp
- Để thầy B bắt kịp. Bất biến: Thay đổi lược đồ của bạn PHẢI có khả năng xử lý các lệnh được sao chép từ một lược đồ phiên bản xuống. Các thay đổi lập chỉ mục đủ điều kiện. Các bổ sung cột đơn giản thường đủ điều kiện. Xóa một cột? chắc là không.
- ATOMICALLY hoán đổi tất cả các khách hàng từ Master A sang Master B. Nếu bạn muốn an toàn (tin tôi đi, bạn làm vậy), bạn nên đảm bảo rằng bản ghi cuối cùng cho A được sao chép thành BEFOREB viết đầu tiên. Nếu bạn cho phép ghi đồng thời lên 2+ bậc thầy, ... thì bạn hiểu rõ hơn về việc sao chép MySQL ở mức DEEP hoặc bạn đang hướng đến một thế giới đau đớn. Đau đớn tột cùng. Như bạn có chuyên mục là AUTOINCREMENT ??? bạn đang gặp khó khăn (trừ khi bạn sử dụng số chẵn trên một chủ và tỷ lệ cược trên khác). KHÔNG tin tưởng bản sao MySQL để "làm điều đúng". Nó KHÔNG thông minh và sẽ không cứu bạn. Nó chỉ kém an toàn hơn một chút so với việc sao chép nhật ký giao dịch nhị phân từ dòng lệnh và phát lại chúng bằng tay. Tuy nhiên, việc ngắt kết nối tất cả các máy khách khỏi máy chủ cũ và chuyển chúng sang máy chủ mới có thể được thực hiện trong vài giây, nhanh hơn rất nhiều so với việc chờ nâng cấp lược đồ nhiều giờ.
- Bây giờ Master B là chủ mới của bạn. Bạn có lược đồ mới. Cuộc sống là tốt. Uống một ly bia; điều tồi tệ nhất đã qua.
- Lặp lại quy trình với Master A, nâng cấp giản đồ của anh ta để anh ta trở thành master phụ mới của bạn, sẵn sàng tiếp quản trong trường hợp master chính của bạn (master B bây giờ) mất điện hoặc vừa lên và chết vì bạn.
Đây không phải là một cách dễ dàng để cập nhật lược đồ. Làm việc được trong môi trường sản xuất nghiêm túc; Vâng, đúng vậy. Làm ơn, làm ơn, làm ơn, nếu có cách dễ dàng hơn để thêm chỉ mục vào bảng MySQL mà không chặn ghi, hãy cho tôi biết.
Googling dẫn tôi đến bài viết này mô tả một kỹ thuật tương tự. Thậm chí tốt hơn, họ khuyên uống cùng một điểm trong quá trình tiến hành (Lưu ý rằng tôi đã viết câu trả lời của mình trước khi đọc bài báo)!
Percona's pt-online-schema-change
Các bài viết tôi liên kết ở trên nói về một công cụ, pt-trực tuyến-schema-thay đổi , các công trình đó như sau:
- Tạo bảng mới với cấu trúc giống như bảng gốc.
- Cập nhật lược đồ trên bảng mới.
- Thêm trình kích hoạt trên bảng gốc để các thay đổi được giữ đồng bộ với bản sao
- Sao chép hàng loạt từ bảng gốc.
- Di chuyển bảng gốc ra khỏi đường và thay thế bằng bảng mới.
- Bỏ bàn cũ.
Tôi chưa bao giờ tự mình thử công cụ. YMMV
RDS
Tôi hiện đang sử dụng MySQL thông qua RDS của Amazon . Đó là một dịch vụ thực sự tiện lợi bao bọc và quản lý MySQL, cho phép bạn thêm các bản sao đã đọc mới chỉ với một nút duy nhất và nâng cấp cơ sở dữ liệu một cách minh bạch trên SKU phần cứng. Nó thực sự tiện lợi. Bạn không có quyền truy cập SUPER vào cơ sở dữ liệu, vì vậy bạn không thể bắt chước trực tiếp với việc sao chép (đây là một phước lành hay lời nguyền?). Tuy nhiên, bạn có thể sử dụng Quảng cáo bản sao đọc để thực hiện các thay đổi giản đồ của mình trên máy nô lệ chỉ đọc, sau đó thăng chức máy chủ đó trở thành chủ nhân mới của bạn. Chính xác là thủ thuật giống như tôi đã mô tả ở trên, chỉ dễ thực hiện hơn rất nhiều. Họ vẫn không giúp được gì nhiều cho bạn. Bạn phải cấu hình lại và khởi động lại ứng dụng của mình.