Truy vấn chậm, truy vấn không hiệu quả hoặc truy vấn chạy lâu là những vấn đề thường xuyên xảy ra với DBA. Chúng luôn có mặt ở khắp mọi nơi, nhưng là một phần tất yếu của cuộc sống đối với bất kỳ ai chịu trách nhiệm quản lý cơ sở dữ liệu.
Thiết kế cơ sở dữ liệu kém có thể ảnh hưởng đến hiệu quả của truy vấn và hiệu suất của nó. Thiếu kiến thức hoặc sử dụng không đúng cách các lệnh gọi hàm, thủ tục được lưu trữ hoặc thói quen cũng có thể gây ra suy giảm hiệu suất cơ sở dữ liệu và thậm chí có thể gây hại cho toàn bộ cụm cơ sở dữ liệu MySQL.
Đối với bản sao master-slave, nguyên nhân rất phổ biến của những vấn đề này là các bảng thiếu chỉ mục chính hoặc phụ. Điều này gây ra độ trễ nô lệ có thể kéo dài trong một thời gian rất dài (trong trường hợp xấu hơn).
Trong loạt bài blog gồm hai phần này, chúng tôi sẽ cung cấp cho bạn một khóa học bổ sung về cách giải quyết việc tối đa hóa các truy vấn cơ sở dữ liệu của bạn trong MySQL để thúc đẩy hiệu quả và hiệu suất tốt hơn.
Luôn thêm Chỉ mục duy nhất vào Bảng của bạn
Các bảng không có khóa chính hoặc khóa duy nhất thường gây ra vấn đề lớn khi dữ liệu lớn hơn. Khi điều này xảy ra, một sửa đổi dữ liệu đơn giản có thể làm đình trệ cơ sở dữ liệu. Thiếu chỉ mục thích hợp và câu lệnh CẬP NHẬT hoặc XÓA đã được áp dụng cho bảng cụ thể, quá trình quét toàn bộ bảng sẽ được MySQL chọn làm kế hoạch truy vấn. Điều đó có thể gây ra I / O đĩa cao để đọc và ghi và làm giảm hiệu suất của cơ sở dữ liệu của bạn. Xem ví dụ bên dưới:
root[test]> show create table sbtest2\G
*************************** 1. row ***************************
Table: sbtest2
Create Table: CREATE TABLE `sbtest2` (
`id` int(10) unsigned NOT NULL,
`k` int(10) unsigned NOT NULL DEFAULT '0',
`c` char(120) NOT NULL DEFAULT '',
`pad` char(60) NOT NULL DEFAULT ''
) ENGINE=InnoDB DEFAULT CHARSET=latin1
1 row in set (0.00 sec)
root[test]> explain extended update sbtest2 set k=52, pad="xx234xh1jdkHdj234" where id=57;
+----+-------------+---------+------------+------+---------------+------+---------+------+---------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+---------+------------+------+---------------+------+---------+------+---------+----------+-------------+
| 1 | UPDATE | sbtest2 | NULL | ALL | NULL | NULL | NULL | NULL | 1923216 | 100.00 | Using where |
+----+-------------+---------+------------+------+---------------+------+---------+------+---------+----------+-------------+
1 row in set, 1 warning (0.06 sec)
Trong khi bảng có khóa chính có kế hoạch truy vấn rất tốt,
root[test]> show create table sbtest3\G
*************************** 1. row ***************************
Table: sbtest3
Create Table: CREATE TABLE `sbtest3` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`k` int(10) unsigned NOT NULL DEFAULT '0',
`c` char(120) NOT NULL DEFAULT '',
`pad` char(60) NOT NULL DEFAULT '',
PRIMARY KEY (`id`),
KEY `k` (`k`)
) ENGINE=InnoDB AUTO_INCREMENT=2097121 DEFAULT CHARSET=latin1
1 row in set (0.00 sec)
root[test]> explain extended update sbtest3 set k=52, pad="xx234xh1jdkHdj234" where id=57;
+----+-------------+---------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+---------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+
| 1 | UPDATE | sbtest3 | NULL | range | PRIMARY | PRIMARY | 4 | const | 1 | 100.00 | Using where |
+----+-------------+---------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
Khóa chính hoặc khóa duy nhất cung cấp thành phần quan trọng cho cấu trúc bảng vì điều này rất quan trọng, đặc biệt khi thực hiện bảo trì trên bảng. Ví dụ:việc sử dụng các công cụ từ Bộ công cụ Percona (chẳng hạn như pt-online-schema-change hoặc pt-table-sync) khuyến nghị rằng bạn phải có các khóa duy nhất. Hãy nhớ rằng KHÓA CHÍNH đã là một khóa duy nhất và khóa chính không thể chứa các giá trị NULL trừ khóa duy nhất. Việc gán giá trị NULL cho Khóa chính có thể gây ra lỗi như,
ERROR 1171 (42000): All parts of a PRIMARY KEY must be NOT NULL; if you need NULL in a key, use UNIQUE instead
Đối với các nút nô lệ, trong một số trường hợp nhất định, khóa chính / khóa duy nhất không có trên bảng do đó là sự khác biệt về cấu trúc bảng. Bạn có thể sử dụng mysqldiff để đạt được điều này hoặc bạn có thể mysqldump --no-data… params và chạy một khác biệt để so sánh cấu trúc bảng của nó và kiểm tra xem có bất kỳ sự khác biệt nào không.
Quét các bảng với các chỉ mục trùng lặp, sau đó loại bỏ nó
Các chỉ số trùng lặp cũng có thể làm giảm hiệu suất, đặc biệt khi bảng chứa một số lượng lớn các bản ghi. MySQL phải thực hiện nhiều lần để tối ưu hóa truy vấn và thực hiện nhiều kế hoạch truy vấn hơn để kiểm tra. Nó bao gồm quét phân phối chỉ mục lớn hoặc thống kê và bổ sung chi phí hiệu suất vì nó có thể gây tranh chấp bộ nhớ hoặc sử dụng bộ nhớ I / O cao.
Giảm cấp cho các truy vấn khi quan sát thấy các chỉ số trùng lặp trên một bảng cũng thuộc tính bão hòa vùng đệm. Điều này cũng có thể ảnh hưởng đến hiệu suất của MySQL khi điểm kiểm tra chuyển các bản ghi giao dịch vào đĩa. Điều này là do việc xử lý và lưu trữ một chỉ mục không mong muốn (thực chất là lãng phí dung lượng trong vùng bảng cụ thể của bảng đó). Hãy lưu ý rằng các chỉ mục trùng lặp cũng được lưu trữ trong vùng bảng cũng phải được lưu trữ trong vùng đệm.
Hãy xem bảng bên dưới chứa nhiều khóa trùng lặp:
root[test]#> show create table sbtest3\G
*************************** 1. row ***************************
Table: sbtest3
Create Table: CREATE TABLE `sbtest3` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`k` int(10) unsigned NOT NULL DEFAULT '0',
`c` char(120) NOT NULL DEFAULT '',
`pad` char(60) NOT NULL DEFAULT '',
PRIMARY KEY (`id`),
KEY `k` (`k`,`pad`,`c`),
KEY `kcp2` (`id`,`k`,`c`,`pad`),
KEY `kcp` (`k`,`c`,`pad`),
KEY `pck` (`pad`,`c`,`id`,`k`)
) ENGINE=InnoDB AUTO_INCREMENT=2048561 DEFAULT CHARSET=latin1
1 row in set (0.00 sec)
và có kích thước là 2,3GiB
root[test]#> \! du -hs /var/lib/mysql/test/sbtest3.ibd
2.3G /var/lib/mysql/test/sbtest3.ibd
Hãy loại bỏ các chỉ số trùng lặp và xây dựng lại bảng với một thay đổi không hoạt động,
root[test]#> drop index kcp2 on sbtest3; drop index kcp on sbtest3 drop index pck on sbtest3;
Query OK, 0 rows affected (0.01 sec)
Records: 0 Duplicates: 0 Warnings: 0
Query OK, 0 rows affected (0.01 sec)
Records: 0 Duplicates: 0 Warnings: 0
Query OK, 0 rows affected (0.01 sec)
Records: 0 Duplicates: 0 Warnings: 0
root[test]#> alter table sbtest3 engine=innodb;
Query OK, 0 rows affected (28.23 sec)
Records: 0 Duplicates: 0 Warnings: 0
root[test]#> \! du -hs /var/lib/mysql/test/sbtest3.ibd
945M /var/lib/mysql/test/sbtest3.ibd
Nó đã có thể tiết kiệm đến ~ 59% kích thước cũ của không gian bảng, thực sự rất lớn.
Để xác định các chỉ mục trùng lặp, bạn có thể sử dụng pt-trùng lặp-kiểm tra để xử lý công việc cho bạn.
Điều chỉnh Nhóm Bộ đệm của bạn
Đối với phần này, tôi chỉ đề cập đến công cụ lưu trữ InnoDB.
Vùng đệm là một thành phần quan trọng trong không gian hạt nhân InnoDB. Đây là nơi InnoDB lưu trữ dữ liệu bảng và chỉ mục khi được truy cập. Nó tăng tốc độ xử lý vì dữ liệu được sử dụng thường xuyên đang được lưu trữ trong bộ nhớ một cách hiệu quả bằng cách sử dụng BTREE. Ví dụ:Nếu bạn có nhiều bảng bao gồm> =100GiB và được truy cập nhiều, thì chúng tôi khuyên bạn nên ủy quyền một bộ nhớ biến động nhanh bắt đầu từ kích thước 128GiB và bắt đầu gán vùng đệm với 80% bộ nhớ vật lý. 80% phải được giám sát hiệu quả. Bạn có thể sử dụng SHOW ENGINE INNODB STATUS \ G hoặc bạn có thể tận dụng phần mềm giám sát như ClusterControl, cung cấp một hệ thống giám sát chi tiết bao gồm vùng đệm và các chỉ số sức khỏe liên quan của nó. Đồng thời đặt biến innodb_buffer_pool_instances cho phù hợp. Bạn có thể đặt giá trị này lớn hơn 8 (mặc định nếu innodb_buffer_pool_size> =1GiB), chẳng hạn như 16, 24, 32 hoặc 64 hoặc cao hơn nếu cần.
Khi theo dõi vùng đệm, bạn cần kiểm tra biến trạng thái chung Innodb_buffer_pool_pages_free, biến này cung cấp cho bạn những suy nghĩ nếu cần điều chỉnh vùng đệm hoặc có thể xem xét nếu cũng có các chỉ mục không mong muốn hoặc trùng lặp tiêu thụ đệm. SHOW ENGINE INNODB STATUS \ G cũng cung cấp một khía cạnh chi tiết hơn về thông tin vùng đệm bao gồm cả vùng đệm riêng của nó dựa trên số lượng innodb_buffer_pool_instances bạn đã đặt.
Sử dụng Chỉ mục FULLTEXT (Nhưng Chỉ khi Có thể áp dụng)
Sử dụng các truy vấn như,
SELECT bookid, page, context FROM books WHERE context like '%for dummies%';
trong đó ngữ cảnh là một cột kiểu chuỗi (char, varchar, text), là một ví dụ về một truy vấn siêu tệ! Việc kéo nội dung lớn của các bản ghi bằng một bộ lọc mà bạn phải tham lam thì kết thúc bằng việc quét toàn bộ bảng, và điều đó thật điên rồ. Cân nhắc sử dụng chỉ mục FULLTEXT. Chỉ mục FULLTEXT có thiết kế chỉ mục đảo ngược. Các chỉ mục đảo ngược lưu trữ danh sách các từ và đối với mỗi từ, một danh sách các tài liệu mà từ đó xuất hiện. Để hỗ trợ tìm kiếm vùng lân cận, thông tin vị trí cho mỗi từ cũng được lưu trữ dưới dạng một byte bù đắp.
Để sử dụng FULLTEXT để tìm kiếm hoặc lọc dữ liệu, bạn cần sử dụng kết hợp cú pháp MATCH () ... AGAINST và không giống như truy vấn ở trên. Tất nhiên, bạn cần chỉ định trường làm trường chỉ mục FULLTEXT của bạn.
Để tạo chỉ mục FULLTEXT, chỉ cần chỉ định FULLTEXT làm chỉ mục của bạn. Xem ví dụ bên dưới:
root[minime]#> CREATE FULLTEXT INDEX aboutme_fts ON users_info(aboutme);
Query OK, 0 rows affected, 1 warning (0.49 sec)
Records: 0 Duplicates: 0 Warnings: 1
root[jbmrcd_date]#> show warnings;
+---------+------+--------------------------------------------------+
| Level | Code | Message |
+---------+------+--------------------------------------------------+
| Warning | 124 | InnoDB rebuilding table to add column FTS_DOC_ID |
+---------+------+--------------------------------------------------+
1 row in set (0.00 sec)
Mặc dù việc sử dụng các chỉ mục FULLTEXT có thể mang lại lợi ích khi tìm kiếm các từ trong ngữ cảnh rất lớn bên trong một cột, nó cũng tạo ra các vấn đề khi sử dụng không đúng cách.
Khi thực hiện tìm kiếm FULLTEXT cho một bảng lớn được truy cập liên tục (trong đó một số yêu cầu của khách hàng đang tìm kiếm các từ khóa khác nhau, duy nhất), nó có thể rất tốn CPU.
Cũng có một số trường hợp mà FULLTEXT không được áp dụng. Xem bài đăng blog bên ngoài này. Mặc dù tôi chưa thử điều này với 8.0 nhưng tôi không thấy bất kỳ thay đổi nào liên quan đến điều này. Chúng tôi khuyên bạn không nên sử dụng FULLTEXT để tìm kiếm trong môi trường dữ liệu lớn, đặc biệt là đối với các bảng có lưu lượng truy cập cao. Nếu không, hãy thử tận dụng các công nghệ khác như Apache Lucene, Apache Solr, tsearch2 hoặc Sphinx.
Tránh sử dụng NULL trong các cột
Các cột chứa giá trị null hoàn toàn ổn trong MySQL. Nhưng nếu bạn đang sử dụng các cột có giá trị null vào một chỉ mục, nó có thể ảnh hưởng đến hiệu suất truy vấn vì trình tối ưu hóa không thể cung cấp kế hoạch truy vấn phù hợp do phân phối chỉ mục kém. Tuy nhiên, có một số cách nhất định để tối ưu hóa các truy vấn liên quan đến giá trị null nhưng tất nhiên, nếu điều này phù hợp với yêu cầu. Vui lòng kiểm tra tài liệu của MySQL về Tối ưu hóa Null. Bạn cũng có thể kiểm tra bài đăng bên ngoài này cũng hữu ích.
Thiết kế cấu trúc bảng và cấu trúc liên kết lược đồ của bạn một cách hiệu quả
Ở một mức độ nào đó, việc chuẩn hóa bảng cơ sở dữ liệu của bạn từ 1NF (Dạng chuẩn đầu tiên) sang 3NF (Dạng chuẩn thứ ba) mang lại cho bạn một số lợi ích về hiệu quả truy vấn vì các bảng chuẩn hóa có xu hướng tránh các bản ghi dư thừa. Lập kế hoạch và thiết kế phù hợp cho các bảng của bạn là rất quan trọng vì đây là cách bạn truy xuất hoặc kéo dữ liệu và trong mỗi hành động này đều phải trả giá. Với các bảng chuẩn hóa, mục tiêu của cơ sở dữ liệu là đảm bảo rằng mọi cột không phải khóa trong mọi bảng đều phụ thuộc trực tiếp vào khóa; toàn bộ chìa khóa và không có gì khác ngoài chìa khóa. Nếu đạt được mục tiêu này, nó sẽ mang lại những lợi ích dưới dạng giảm thiểu dư thừa, ít dị thường hơn và cải thiện hiệu quả.
Mặc dù việc chuẩn hóa bảng của bạn có nhiều lợi ích, nhưng không có nghĩa là bạn cần chuẩn hóa tất cả các bảng của mình theo cách này. Bạn có thể triển khai thiết kế cho cơ sở dữ liệu của mình bằng Star Schema. Thiết kế bảng của bạn bằng Star Schema có lợi ích là các truy vấn đơn giản hơn (tránh kết hợp chéo phức tạp), dễ dàng truy xuất dữ liệu để báo cáo, mang lại hiệu suất tăng do không cần sử dụng kết hợp hoặc liên kết phức tạp hoặc tổng hợp nhanh. Lược đồ hình sao rất đơn giản để thực hiện, nhưng bạn cần phải lập kế hoạch cẩn thận vì nó có thể tạo ra các vấn đề và bất lợi lớn khi bảng của bạn lớn hơn và yêu cầu bảo trì. Lược đồ hình sao (và các bảng bên dưới của nó) dễ gặp các vấn đề về tính toàn vẹn của dữ liệu, vì vậy bạn có thể có khả năng cao là nhóm dữ liệu của bạn là dư thừa. Nếu bạn cho rằng bảng này phải không đổi (cấu trúc và thiết kế) và được thiết kế để sử dụng hiệu quả truy vấn, thì đó là một trường hợp lý tưởng cho cách tiếp cận này.
Kết hợp các thiết kế cơ sở dữ liệu của bạn (miễn là bạn có thể xác định và xác định loại dữ liệu nào phải được kéo trên các bảng của mình) là rất quan trọng vì bạn có thể hưởng lợi với các truy vấn hiệu quả hơn và cũng như giúp DBA sao lưu, bảo trì và khôi phục.
Thoát khỏi Dữ liệu cũ và Cố định
Gần đây, chúng tôi đã viết một số Phương pháp hay nhất để Lưu trữ Cơ sở dữ liệu của Bạn trên Đám mây. Nó bao gồm cách bạn có thể tận dụng lợi thế của việc lưu trữ dữ liệu trước khi nó lên đám mây. Vậy làm cách nào để loại bỏ dữ liệu cũ hoặc lưu trữ dữ liệu cũ và liên tục của bạn giúp truy vấn hiệu quả? Như đã nêu trong blog trước của tôi, có những lợi ích đối với các bảng lớn hơn được sửa đổi liên tục và chèn thêm dữ liệu mới, không gian bảng có thể phát triển nhanh chóng. MySQL và InnoDB hoạt động hiệu quả khi các bản ghi hoặc dữ liệu tiếp giáp với nhau và có ý nghĩa đối với hàng tiếp theo của nó trong bảng. Có nghĩa là, nếu bạn không có bản ghi cũ không cần sử dụng nữa, thì trình tối ưu hóa không cần đưa bản ghi đó vào thống kê để cung cấp kết quả hiệu quả hơn nhiều. Có ý nghĩa, phải không? Ngoài ra, hiệu quả truy vấn không chỉ ở phía ứng dụng, nó cũng cần phải xem xét hiệu quả của nó khi thực hiện sao lưu và khi bảo trì hoặc chuyển đổi dự phòng. Ví dụ:nếu bạn có một truy vấn không tốt và dài có thể ảnh hưởng đến thời gian bảo trì của bạn hoặc chuyển đổi dự phòng, đó có thể là một vấn đề.
Bật tính năng ghi nhật ký truy vấn khi cần thiết
Luôn đặt nhật ký truy vấn chậm MySQL của bạn phù hợp với nhu cầu tùy chỉnh của bạn. Nếu bạn đang sử dụng Máy chủ Percona, bạn có thể tận dụng tính năng ghi nhật ký truy vấn chậm mở rộng của họ. Nó cho phép bạn xác định một cách tùy chỉnh các biến nhất định. Bạn có thể lọc kết hợp các loại truy vấn như full_scan, full_join, tmp_table, v.v. Bạn cũng có thể chỉ định tốc độ ghi truy vấn chậm thông qua biến log_slow_rate_type và nhiều biến khác.
Tầm quan trọng của việc bật đăng nhập truy vấn trong MySQL (chẳng hạn như truy vấn chậm) có lợi cho việc kiểm tra các truy vấn của bạn để bạn có thể tối ưu hóa hoặc điều chỉnh MySQL của mình bằng cách điều chỉnh một số biến nhất định phù hợp với yêu cầu của bạn. Để bật nhật ký truy vấn chậm, hãy đảm bảo rằng các biến này đã được thiết lập:
- long_query_time - chỉ định giá trị phù hợp cho khoảng thời gian mà các truy vấn có thể mất. Nếu các truy vấn mất hơn 10 giây (mặc định), nó sẽ chuyển xuống tệp nhật ký truy vấn chậm mà bạn đã chỉ định.
- slow_query_log - để kích hoạt nó, hãy đặt nó thành 1.
- slow_query_log_file - đây là đường dẫn đích cho tệp nhật ký truy vấn chậm của bạn.
Nhật ký truy vấn chậm rất hữu ích cho việc phân tích truy vấn và chẩn đoán các truy vấn không hợp lệ gây ra lỗi ngừng hoạt động, chậm trễ do nô lệ, truy vấn chạy lâu, sử dụng nhiều bộ nhớ hoặc CPU hoặc thậm chí khiến máy chủ gặp sự cố. Nếu bạn sử dụng pt-query-dig hoặc pt-index-using, hãy sử dụng tệp nhật ký truy vấn chậm làm mục tiêu nguồn của bạn để báo cáo các truy vấn này như nhau.
Kết luận
Chúng tôi đã thảo luận một số cách bạn có thể sử dụng để tối đa hóa hiệu quả truy vấn cơ sở dữ liệu trong blog này. Trong phần tiếp theo này, chúng ta sẽ thảo luận thêm về các yếu tố có thể giúp bạn tối đa hóa hiệu suất. Hãy theo dõi!