Tại sao MySQL sẽ thực hiện I / O đồng bộ nối tiếp?


8

Khi xem xét một truy vấn đặc biệt khó chịu trên các bảng MyISAM, phải mất một thời gian dài để thực thi trong một số trường hợp, tôi đã lưu ý rằng MySQL dường như để lộ một mẫu I / O khá lạ: khi thực hiện một truy vấn duy nhất và phải thực hiện một truy vấn quan trọng số lượng I / O (ví dụ để quét bảng hoặc khi bộ đệm trống do kết quả của echo 3 > /proc/sys/vm/drop_cachescác chỉ mục cần được tải ra khỏi đĩa trước), kích thước hàng đợi cho thiết bị khối bên dưới gần giá trị 1, với hiệu suất vượt trội của chỉ 4-5 MB / s:

root@mysql-test:~# iostat -xdm 5 /dev/sda
Linux 3.2.0-40-generic (mysql-test)  04/30/2014      _x86_64_        (4 CPU)

Device:         rrqm/s   wrqm/s     r/s     w/s    rMB/s    wMB/s avgrq-sz avgqu-sz   await r_await w_await  svctm  %util
sda               0.14    24.82   18.26   88.79     0.75     4.61   102.56     2.83   26.39   19.29   27.85   2.46  26.31

Device:         rrqm/s   wrqm/s     r/s     w/s    rMB/s    wMB/s avgrq-sz avgqu-sz   await r_await w_await  svctm  %util
sda               0.00    69.29  151.52   72.73     5.31     0.59    53.95     1.21    5.39    7.84    0.29   4.39  98.51

Device:         rrqm/s   wrqm/s     r/s     w/s    rMB/s    wMB/s avgrq-sz avgqu-sz   await r_await w_await  svctm  %util
sda               0.00   153.06  144.29  174.69     4.96     1.36    40.54     1.39    4.36    8.91    0.60   3.15 100.49

Device:         rrqm/s   wrqm/s     r/s     w/s    rMB/s    wMB/s avgrq-sz avgqu-sz   await r_await w_await  svctm  %util
sda               0.00   105.75  150.92  109.03     4.53     0.85    42.41     1.29    4.96    8.15    0.54   3.90 101.36

Device:         rrqm/s   wrqm/s     r/s     w/s    rMB/s    wMB/s avgrq-sz avgqu-sz   await r_await w_await  svctm  %util
sda               0.00    48.89  156.36   51.72     5.28     0.76    59.38     1.28    6.16    8.02    0.55   4.77  99.23

Mặc dù 150 IOPS chỉ đơn giản là những gì một đĩa đơn trong cấu hình đã cho có khả năng phân phối theo I / O ngẫu nhiên, kết quả vẫn thực sự làm tôi ngạc nhiên vì tôi mong đợi MySQL có thể chạy I / O không đồng bộ để đọc và tìm nạp số lượng lớn các khối đồng thời thay vì đọc và đánh giá từng khối một, bỏ qua hiệu quả song song hóa có sẵn trong các cấu hình RAID. Quyết định thiết kế hoặc tùy chọn cấu hình nào chịu trách nhiệm cho việc này? Đây có phải là một vấn đề cụ thể nền tảng?

Trong khi tôi đã thử nghiệm điều này với các bảng MyISAM lớn, tôi thấy các hiệu ứng tương tự với các bảng tương tự được chuyển đổi thành InnoDB (mặc dù không tệ như vậy, truy vấn mẫu vẫn mất 20-30 giây với phần lớn thời gian dành cho việc đọc đĩa với độ dài hàng đợi là 1) sau khi tôi khởi động lại daemon mysql và do đó các vùng đệm trống. Tôi cũng đã xác minh rằng vấn đề tương tự vẫn tồn tại trên 5.6 GA và mốc 5,7 hiện tại - miễn là tôi đang sử dụng một chuỗi truy vấn duy nhất, MySQL dường như không thể song song hóa các hoạt động I / O cần thiết cho xử lý truy vấn.


Theo yêu cầu một số chi tiết bổ sung về kịch bản. Hành vi có thể được quan sát với vô số loại truy vấn. Tôi đã tùy ý chọn một cái để kiểm tra thêm mà đọc phần nào như thế này:

SELECT herp.id, herp.firstname, herp.lastname, derp.label, herp.email, 
(SELECT CONCAT(label, " (", zip_code, " ", city,")" ) FROM subsidiaries WHERE subsidiaries.id=herp.subsidiary_id ) AS subsidiary, 
(SELECT COUNT(fk_herp) from herp_missing_data WHERE fk_herp=herp.id) AS missing_data
FROM herp LEFT JOIN derp ON derp.id=herp.fk_derp
WHERE (herp.fk_pools='123456')  AND herp.city LIKE '%Some City%' AND herp.active='yes' 
ORDER BY herp.id desc LIMIT 0,10;

Tôi biết rằng nó có một số chỗ để tối ưu hóa, nhưng tôi đã quyết định để nó ở đó vì một số lý do và tập trung vào việc tìm một lời giải thích chung cho mẫu I / O bất ngờ mà tôi đang thấy.

Các bảng được sử dụng có một loạt dữ liệu trong đó:

mysql> select table_name, engine, table_rows, data_length, index_length from information_schema.tables WHERE tables.TABLE_SCHEMA = 'mydb' and tables.table_name in ( 'herp', 'derp', 'missing_data', 'subsidiaries');
+-------------------------+--------+------------+-------------+--------------+
| table_name              | engine | table_rows | data_length | index_length |
+-------------------------+--------+------------+-------------+--------------+
| derp                    | MyISAM |      14085 |     1118676 |       165888 |
| herp                    | MyISAM |     821747 |   828106512 |    568057856 |
| missing_data            | MyISAM |    1220186 |    15862418 |     29238272 |
| subsidiaries            | MyISAM |       1499 |     6490308 |       103424 |
+-------------------------+--------+------------+-------------+--------------+
4 rows in set (0.00 sec)

Bây giờ khi tôi đang chạy truy vấn ở trên các bảng này, tôi nhận được thời gian thực hiện hơn 1 phút trong khi hệ thống dường như liên tục bận đọc dữ liệu ra khỏi đĩa với một luồng.

Cấu hình để thực hiện truy vấn mẫu (mất 1 phút 9,17 giây trong ví dụ này) trông như thế này:

mysql> show profile for query 1;
+--------------------------------+-----------+
| Status                         | Duration  |
+--------------------------------+-----------+
| starting                       |  0.000118 |
| Waiting for query cache lock   |  0.000035 |
| init                           |  0.000033 |
| checking query cache for query |  0.000399 |
| checking permissions           |  0.000077 |
| checking permissions           |  0.000030 |
| checking permissions           |  0.000031 |
| checking permissions           |  0.000035 |
| Opening tables                 |  0.000158 |
| init                           |  0.000294 |
| System lock                    |  0.000056 |
| Waiting for query cache lock   |  0.000032 |
| System lock                    |  0.000116 |
| optimizing                     |  0.000063 |
| statistics                     |  0.001964 |
| preparing                      |  0.000104 |
| Sorting result                 |  0.000033 |
| executing                      |  0.000030 |
| Sending data                   |  2.031349 |
| optimizing                     |  0.000054 |
| statistics                     |  0.000039 |
| preparing                      |  0.000024 |
| executing                      |  0.000013 |
| Sending data                   |  0.000044 |
| optimizing                     |  0.000017 |
| statistics                     |  0.000021 |
| preparing                      |  0.000019 |
| executing                      |  0.000013 |
| Sending data                   | 21.477528 |
| executing                      |  0.000070 |
| Sending data                   |  0.000075 |
| executing                      |  0.000027 |
| Sending data                   | 45.692623 |
| end                            |  0.000076 |
| query end                      |  0.000036 |
| closing tables                 |  0.000109 |
| freeing items                  |  0.000067 |
| Waiting for query cache lock   |  0.000038 |
| freeing items                  |  0.000080 |
| Waiting for query cache lock   |  0.000044 |
| freeing items                  |  0.000037 |
| storing result in query cache  |  0.000033 |
| logging slow query             |  0.000103 |
| cleaning up                    |  0.000073 |
+--------------------------------+-----------+
44 rows in set, 1 warning (0.00 sec)

Bạn có một trường hợp thử nghiệm lặp lại (lý tưởng đơn giản) bạn có thể giải thích chi tiết hơn không? Ví dụ: một truy vấn tạo ra hành vi này? Trong bất kì trường hợp nào? Bạn đã bắt đầu con đường đó với "echo 3> ..." & "khởi động lại daemon mysql" nhưng không đi sâu vào chi tiết.
Scott Leadley

@ScottLeadley cảm ơn bạn đã xem xét điều này. Tôi không nghĩ rằng tôi sẽ có thể làm cho nó "đơn giản" - vấn đề chỉ có thể quan sát được nếu một lượng lớn dữ liệu sẽ cần phải đọc cho một truy vấn duy nhất nó chủ yếu là I / O ngẫu nhiên. Các bảng và truy vấn khá đơn giản và trong khi tôi có thể đăng các văn bản DDL và Truy vấn, tôi nghi ngờ bất kỳ ai cũng có thể sao chép nó ngay lập tức trừ khi dữ liệu bảng / chỉ mục đã tăng lên hàng trăm Megabyte.
syirecton-dj

Như bạn đã đề cập, 5 ms chờ đợi để đọc phù hợp với độ trễ quay trung bình của một đĩa 5400 vòng / phút. Tìm kiếm sự tranh chấp khi đọc "một lượng lớn dữ liệu ... chủ yếu là I / O ngẫu nhiên" sẽ giải thích cho điều đó. Đối với RAID, bạn đã đề cập đến nó, nhưng chưa đưa ra bất kỳ chi tiết nào về cấu hình cụ thể này.
Scott Leadley

Không chắc chắn tôi có thể giúp bạn trực tiếp, vì tôi không chạy cấu hình của bạn. Nhưng quy tắc của StackExchange là một câu hỏi thực sự hay được chú ý nhiều hơn là tiền thưởng. Viết câu hỏi hoàn hảo
Scott Leadley

@ScottLeadley việc chờ đợi 5 ms chủ yếu là do độ trễ của hệ thống lưu trữ được sử dụng. Tôi đã thử nghiệm điều này trong các tình huống khác nhau - từ RAID10 4 đĩa đơn giản đến trình lưu trữ lưu trữ theo tầng với kệ 16 đĩa và sao lưu SSD, kết quả cho thấy tải I / O không song song và do đó bị giới hạn độ trễ. Mà tôi cảm thấy sai về cơ bản. Tôi đã thêm các chi tiết truy vấn vào câu hỏi, nhưng tôi chưa tin rằng chúng sẽ giúp ích rất nhiều.
syirecton-dj

Câu trả lời:


8

Trước tiên, hãy để tôi làm rõ bằng cách xác nhận rằng MyISAM không thực hiện I / O không đồng bộ, nhưng InnoDB làm và sẽ mặc định từ MySQL 5.5. Trước 5.5, nó đã sử dụng "AIO mô phỏng" bằng cách sử dụng các luồng công nhân.

Tôi nghĩ cũng cần phân biệt giữa ba tình huống:

  1. Nhiều truy vấn thực thi cùng một lúc
  2. Một truy vấn duy nhất thực hiện song song
  3. Một số loại logic đọc trước để quét bảng / trường hợp rõ ràng trong đó các trang tiếp theo được biết đến.

Đối với (1) I / O sẽ có thể thực thi song song cho việc này. Có một số giới hạn với MyISAM: khóa bảng và khóa toàn cầu bảo vệ key_buffer(bộ đệm chỉ mục). InnoDB trong MySQL 5.5+ thực sự tỏa sáng ở đây.

Đối với (2) điều này hiện không được hỗ trợ. Một trường hợp sử dụng tốt sẽ là phân vùng, trong đó bạn có thể tìm kiếm song song từng bảng được phân vùng.

Đối với (3) InnoDB có đọc trước tuyến tính để đọc toàn bộ (nhóm 64 trang) nếu> 56 trang được đọc (đây là cấu hình), nhưng vẫn còn chỗ để tăng cường hơn nữa. Facebook đã viết về việc triển khai đầu đọc logic trong chi nhánh của họ (với mức tăng hoàn hảo gấp 10 lần trên bảng).


Cảm ơn, điều này cho tôi thêm một số hiểu biết về những gì tôi đang nhìn thấy. Điều đó thường có nghĩa là MyISAM không thể sử dụng nhiều hơn một IOPS giá trị đĩa cho một tải đơn luồng? Tôi không thể tìm thấy bất kỳ tài liệu tham khảo nào trong tài liệu này - bạn có tình cờ có thứ gì đó tiện dụng không?
syirecton-dj

Đúng. Tôi không thể nghĩ ra một vị trí trong các tài liệu nơi này sẽ là.
Morgan Tocker

2

Tôi hy vọng missing_datakhông phải là MyISAM vì một bảng MyISAM trống thường có 1024 byte .MYI. Một kích thước byte khác không được mong đợi của MyISAM. Một byte không .MYIcó vẻ hơi đáng sợ đối với tôi.

Nếu bạn chạy truy vấn siêu dữ liệu này

select table_name, table_rows, data_length, index_length, engine
from information_schema.tables
WHERE tables.TABLE_SCHEMA = 'mydb'
and tables.table_name = 'missing_data';

và động cơ của bảng đó là MyISAM, bạn cần sửa chữa nó.

PHỤ CHÚ Ý: Nếu engineNULL, đó là một cái nhìn. Nếu đó là chế độ xem hoặc không phải MyISAM, vui lòng bỏ qua phần còn lại của bài đăng của tôi và thêm thông tin đó vào câu hỏi. Nếu bảng là MyISAM, hãy đọc tiếp ...

Theo truy vấn siêu dữ liệu của bạn, missing_data.MYDlà khoảng 46M.

Đầu tiên, chạy cái này

SHOW CREATE TABLE mydb.missing_data\G

Bạn sẽ nhận được mô tả bảng hoặc thông báo lỗi có nội dung như

ERROR 126 (HY000): Incorrect key file for table ...

Nếu bạn nhận được mô tả bảng và đó là MyISAM, vui lòng chạy

OPTIMIZE TABLE mydb.missing_data;

Nó sẽ tạo lại bảng không có phân mảnh và tính toán thống kê chỉ số mới. Nếu điều đó không hiệu quả thì hãy thử:

REPAIR TABLE mydb.missing_data;

Điều đó sẽ tạo lại các trang chỉ mục cho MyISAM.

Để an toàn (nếu sử dụng MySQL 5.6), hãy chạy nó sau khi sửa chữa

FLUSH TABLES mydb.missing_data;

Câu hỏi của bạn

Các chỉ mục của bảng của bạn có thể không được tải vào bộ nhớ nếu Trình tối ưu hóa truy vấn MySQL quyết định không sử dụng. Nếu mệnh đề WHERE của bạn chỉ ra số lượng hàng đáng kể phải được đọc từ các chỉ mục, Trình tối ưu hóa truy vấn MySQL sẽ thấy rằng khi xây dựng kế hoạch EXPLAIN và quyết định sử dụng quét toàn bộ bảng thay thế.

Các thao tác I / O song song trên bảng MyISAM là không thể đạt được vì không thể định cấu hình được.

InnoDB có thể được điều chỉnh để tăng hiệu suất như thế.


Tôi phải xác nhận lại một lần nữa: Nếu mydb.missing_data là MyISAM và có chỉ số byte bằng 0 thì chắc chắn có điều gì đó không ổn.
RolandoMySQLDBA

Tôi đã cập nhật dữ liệu để mạch lạc hơn - giờ đây nó hiển thị kết quả chỉ có MyISAM từ một máy chủ duy nhất để mọi người không bị nhầm lẫn.
syirecton-dj
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.