Tạo một chỉ mục trên một bảng sản xuất MySQL khổng lồ mà không cần khóa bảng


104

Tôi cần tạo chỉ mục trên bảng MySQL ~ 5 triệu hàng. Đó là một bảng sản xuất và tôi sợ sẽ có một khối hoàn chỉnh mọi thứ nếu tôi chạy câu lệnh CREATE INDEX ...

Có cách nào để tạo chỉ mục đó mà không chặn chèn và chọn không?

Chỉ cần tự hỏi tôi đã không dừng lại, tạo chỉ mục và khởi động lại hệ thống của mình!


1
đảm bảo myisam_sort_buffer_size và myisam_max_sort_file_size của bạn đủ lớn.
Jon Black

Câu trả lời:


130

[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.


3
pt-online-schema-change hoạt động tuyệt vời ngay cả trong bản sao master-slave. Tôi đã sử dụng nó để thực hiện di chuyển trực tiếp trên một bảng ghi 20 triệu + bận đọc trên db chính sản xuất của chúng tôi với 2 nô lệ sao chép mà không gặp trục trặc hoặc thời gian chết. Phải mất một chút thời gian để chuẩn bị tập lệnh và tôi thường phải tạo tệp .sql chứa thay đổi SQL thô và tệp .sh dưới dạng trình bao bọc để chạy cùng một SQL nhưng ở định dạng phân đoạn (không có BẢNG ĐIỀU KHIỂN). Bạn có thể chạy nhiều lệnh với pt-online-schema-change bằng cách xâu chuỗi chúng lại và phân tách bằng dấu phẩy.
Alex Le

-1; Tôi không biết về các phiên bản cũ hơn, nhưng tôi biết rằng việc tạo chỉ mục không chặn DML đồng thời trong MySQL 5.6+ (mà một RC đã tồn tại vào thời điểm câu trả lời này được viết và đã được phát hành chính thức khi câu trả lời này được kéo dài được chỉnh sửa vào tháng 5 năm 2013) vì tôi đã dựa vào điều này để chạy các tác phẩm tạo chỉ mục nhiều giờ trên các bảng sản xuất trong khi vẫn chấp nhận chèn. Và mặc dù bạn thể đúng về việc chặn DML tạo chỉ mục trong 5.5 trở xuống, nhưng độ trễ dưới giây được trình bày ở đây không hoàn toàn thuyết phục.
Mark Amery,

@MarkAmery - hành vi chặn là hành vi chặn và 400ms là vĩnh viễn. MySQL 5.5 khối để cập nhật chỉ mục. Xây dựng một cơ sở dữ liệu thử nghiệm lớn hơn và nó sẽ chặn trong vài giây, vài giờ hoặc vài ngày. Tôi đã viết bài đăng này trước khi MySQL 5.6 có các bản cập nhật lược đồ trực tuyến, vì vậy nội dung gốc của tôi không phản ánh thực tế đó. Tôi đã cập nhật bài đăng để phản ánh thông tin mới có sẵn.
Dave Dopson

@DaveDopson, bạn có chắc chắn 100% rằng chỉ các hoạt động CẬP NHẬT mới bị chặn không?
toto_tico

Đó là trường hợp của phiên bản tôi đã thử nghiệm.
Dave Dopson

67

Như bài đăng trên blog này đã phác thảo, ALTER TABLEcơ chế InnoDB đã được thiết kế lại hoàn toàn cho MySQL 5.6.

(Để có cái nhìn tổng quan độc quyền về chủ đề này, tài liệu MySQL có thể cung cấp một buổi chiều đáng đọc.)

Để thêm chỉ mục vào bảng mà không có khóa dẫn đến bật UPDATE/ INSERT, có thể sử dụng định dạng câu lệnh sau:

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


16

Bản cập nhật MySQL 5.6 (feb 2013): Giờ đây, bạn có thể thực hiện các thao tác đọc và ghi khi một chỉ mục đang được tạo ngay cả với các bảng InnoDB - http://dev.mysql.com/doc/refman/5.6/en/innodb-create-index -overview.html

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.

và:

Trong MySQL 5.6, tính năng này trở nên tổng quát hơn: bạn có thể đọc và ghi vào các bảng trong khi một chỉ mục đang được tạo và nhiều loại hoạt động ALTER TABLE khác có thể được thực hiện mà không cần sao chép bảng, không chặn hoạt động DML hoặc cả hai. Do đó, trong MySQL 5.6 trở lên, chúng tôi thường gọi tập hợp các tính năng này là DDL trực tuyến hơn là Tạo chỉ mục nhanh.

từ http://dev.mysql.com/doc/refman/5.6/en/glossary.html#glos_fast_index_creation


Vậy thì phân tích của Dave có thể được giải thích như thế nào?
Nikhil Sahu

1
@NikhilSahu Dave rõ ràng không thử nghiệm trên MySQL 5.6 mà trên một số phiên bản cũ hơn. Lưu ý rằng 5.6 vẫn chưa được phát hành vào thời điểm Dave đăng bản sửa đổi ban đầu cho câu trả lời của mình.
Mark Amery,

+1. Phân tích của tôi là trên MySQL 5.5 (phiên bản mới nhất có sẵn vào năm 2013). Tôi đang cập nhật câu trả lời của mình để phản ánh các khả năng mới trong MySQL 5.6.
Dave Dopson

3

pt-online-schema-change là cách tốt nhất nếu bạn thực sự muốn đảm bảo rằng việc di chuyển sẽ không làm hỏng trang web.

Như tôi đã viết trong nhận xét ở trên, tôi có một số kinh nghiệm với pt-online-schema-change trong sản xuất. Chúng ta có bảng chính gồm 20 triệu bản ghi + và một bản ghi chính -> 2 nô lệ sao chép chỉ đọc. Tôi đã thực hiện ít nhất hàng chục lần di chuyển với pt-online-schema-change từ việc thêm một cột mới, thay đổi bộ ký tự, đến việc thêm một số chỉ số. Chúng tôi cũng phục vụ rất nhiều lưu lượng truy cập trong suốt thời gian di chuyển và chúng tôi không gặp trục trặc nào. Tất nhiên, bạn phải kiểm tra tất cả các tập lệnh rất kỹ lưỡng trước khi chạy trên sản xuất.

Tôi đã cố gắng tập hợp hàng loạt các thay đổi thành 1 tập lệnh để pt-online-schema-change chỉ phải sao chép dữ liệu một lần. Và hãy rất cẩn thận với việc thay đổi tên cột vì bạn sẽ làm mất dữ liệu của mình. Tuy nhiên, thêm một chỉ mục sẽ ổn.


Tôi không đồng ý với đề xuất không đủ tiêu chuẩn của bạn về pt-online-schema-change. Nó tuyệt vời, nhưng quá mức cần thiết đối với nhiều tình huống mà khả năng DDL trực tuyến của MySQL 5.6+ đã hoạt động tốt. Nó cũng có những hạn chế (như không chơi tốt với trình kích hoạt) và tăng gấp đôi số lượng ghi cần thiết cho mỗi lần chèn vào bảng ban đầu trong khi đang tiến hành thay đổi giản đồ. Nó sẽ đánh thuế đĩa của bạn nhiều hơn đáng kể so với một thay đổi giản đồ trực tuyến thông thường, và do đó có khả năng "hạ bệ trang web của bạn" trong những trường hợp chỉ chạy thay đổi giản đồ theo cách đơn giản sẽ hoạt động tốt.
Mark Amery vào

Tôi đã viết dựa trên kinh nghiệm thực tế của mình với pt-online-schema-change vào thời điểm đó nên tôi không chắc tại sao bạn lại gọi đề xuất của tôi là "không đủ tiêu chuẩn". Chúng tôi đã có ít nhất hơn 1000 khách truy cập trên trang web tại bất kỳ thời điểm nào khi tôi chạy các thay đổi giản đồ và tất nhiên, IO đĩa đang bị đánh thuế, nhưng trang web của chúng tôi không bị phá sản. Có bộ nhớ đệm tốt cũng giúp ích. Tôi chưa sử dụng MySQL 5.6+ DDL trực tuyến nhưng theo kinh nghiệm của tôi, pt-online-schema-change đã làm tốt công việc của nó trong trường hợp của chúng tôi.
Alex Le,

1
@AlexYe Yikes, ý tôi là "không đủ tiêu chuẩn" theo nghĩa "không có bảo lưu" chứ không phải là "được đưa ra bởi một người không đủ tiêu chuẩn để nhận xét" - cách giải thích thứ hai đã không xảy ra với tôi cho đến khi tôi thấy nhận xét của bạn và chắc chắn là không 'không phải những gì tôi dự định! tức là tôi đã nói rằng mặc dù pt-online-schema-changelà một công cụ hữu ích, nhưng có rất nhiều tình huống trong đó DDL trực tuyến thông thường cũng tốt và một số ít nơi nó tốt hơn, vì vậy bất kỳ khuyến nghị nào về nó nên được cẩn thận thay vì phổ biến.
Mark Amery,
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.