#6 Học database qua tip & trick – và cái giá mình phải trả
Đây là một phần trong series mình chia sẻ về những gì mình đã làm khi xây dựng và vận hành hạ tầng backend trên AWS cho công ty. Không phải là best practice hoàn hảo, cũng không phải kiến thức quá cao siêu. Chỉ đơn giản là những gì mình đã học được, thử nghiệm và áp dụng trong quá trình làm việc hằng ngày.
Mình là một developer đã gần 10 năm kinh nghiệm, cũng từng đó năm làm việc với cơ sở dữ liệu. Mình đa số làm việc với các cơ sở dữ liệu dạng quan hệ như Postgresql, Oracle, SQL Server, Mysql. Nói là vậy, nhưng cũng chỉ đơn giản là vài câu select cơ bản, rồi insert, update, delete, không hiểu quá sâu về bản chất cũng như thành phần bên dưới của nó.

Những lời khuyên quen thuộc
Nếu các bạn tìm trên internet, cách để tối ưu một câu lệnh SQL, không khó để tìm ra các lời khuyên như bên dưới:
Đừng nên select tất cả các cột , select ít cột thôi thì câu lệnh query sẽ nhanh hơn nhiều
Table ít bản ghi thì câu lệnh sẽ nhanh
Nếu câu query mà có sort by trên cột nào thì đánh index trên cột đấy
Câu lệnh mà chậm thì có thể nghĩ ngay tới partitioning hoặc sharding cho cơ sở dữ liệu
Thay đổi thứ tự câu lệnh sẽ tăng tốc hiệu năng của câu SQL
Table bị phân mảnh luôn không tốt, ảnh hưởng tới hiệu năng, phải chống phân mảnh
Thực sự ở đây, mình không đánh giá sự đúng sai của những lời khuyên này, nhưng thường mình áp dụng xong rồi quên luôn, chả nhớ những cái tip trick này nữa, rồi sau đó một vài tháng lại phải tìm lại.
Các bạn không nhầm đâu, đó là cách làm việc của mình trong nhiều năm liền, và mình tin cũng có nhiều người tìm thấy mình trong đó.
Tới một ngày
Rồi một ngày, mình xem các video trên YouTube hướng dẫn về tối ưu cơ sở dữ liệu của anh Trần Quốc Huy (mình thề không phải PR cho ông anh này đâu nhé, nhưng thực sự có những video đáng xem =)))), mình ấn tượng nhất câu nói của anh:
Trong cơ sở dữ liệu, khi bạn biết về chiến lược thực thi, thì mấy cái tip trick trên mạng đều là vớ vẩn hết
Thế rồi mình mới hiểu ra tại sao trước đây mình luôn có một nỗi sợ khi làm việc hoặc phỏng vấn liên quan tới database. Lúc nào mình cũng cảm thấy có một cái gì đó như kiểu “điểm mù”, kiểu như: đừng nhắc tới nó, tôi chỉ biết vài câu select thôi, please.
Thì ra khi mình học, mình toàn theo kiểu tip, trick, syntax với từng loại cơ sở dữ liệu. Chính nó là nguyên nhân làm mình không hiểu bản chất, chỉ biết phần ngọn mà không biết dưới gốc nó có gì.
Khi mình chạy một câu query, điều gì diễn ra bên dưới? Cái gì tốn thời gian? Vì sao lại tốn thời gian?
Tại sao dùng Oracle bạn phải trả phí khá cao, trong khi các open source như Postgresql hay Mysql đều ngon? tự nhiên bỏ cả đống tiền ra mua license có bị điên không ?
Tại sao Postgresql của bạn lại bị phân mảnh và có nên dùng VACUUM không?
Tại sao khi mình DELETE bản ghi mà dung lượng bảng không đổi?
Khi bạn hiểu được cái gì thực sự diễn ra bên dưới, mọi câu hỏi trên đều trở nên sáng tỏ.
Một chút cơ bản
Cái này các bạn có thể search được dễ dàng, nhưng mình sẽ nhắc lại vì nó rất quan trọng.
Đơn vị nhỏ nhất của cơ sở dữ liệu không phải là từng bản ghi mà là page (block). Mỗi page có dung lượng tối đa khoảng 8KB.
Tưởng tượng nó như một trang giấy và mình ghi từng dòng trên đó. Khi mình muốn lấy một dòng, thì bắt buộc phải lấy toàn bộ các trang giấy (page) từ ổ đĩa (disk) lên RAM rồi mới lấy dòng đó ra.
Cơ sở dữ liệu chỉ làm việc với page (block) chứ không làm việc trực tiếp với bản ghi.
Một câu query nhanh hay chậm phụ thuộc vào số lượng page (block) mà nó phải scan.
Trong Postgresql, khi bạn gõ lệnh bên dưới, sẽ hiện ra page của dòng đó:
select ctid, * from my_table;
Bản chất khi bạn đánh index một cột trong một bảng, chỉ là nó sẽ tạo ra một bảng khác, với dữ liệu của cột được sắp xếp, kèm theo thông tin về page và vị trí của record trong page.
Execution plan
Một câu lệnh query nhanh hay chậm thì phụ thuộc vào chiến lược thực thi (execution plan). Mỗi loại cơ sở dữ liệu có các thuật toán khác nhau.
Lưu ý rằng không phải tất cả execution plan đều là tối ưu nhất (chỉ gần như thôi).
Các bước thực hiện một query là:
-
Kiểm tra syntax của câu SQL (thiếu FROM là trả lỗi luôn)
-
Kiểm tra tính đúng đắn (tên table, tên cột có đúng không)
-
Kiểm tra execution plan có trong cache chưa
-
Nếu có thì dùng luôn
-
Nếu chưa thì phân tích các chiến lược có thể xảy ra
-
Tạo ra chi tiết các bước thực hiện
-
-
Thực thi câu lệnh SQL
-
Trả về kết quả
Trong các bước này, thường bước 3 và 4 là tốn nhiều thời gian nhất.
Trong Postgresql, bạn có thể dùng câu lệnh để xem chiến lược thực thi:
EXPLAIN ANALYZE <your_query>;
Nhờ câu lệnh này, bạn có thể tối ưu câu query của mình, xác định được các index còn thiếu thay vì chỉ mù mờ đoán mò.
Mình đã ổn hơn
Thực sự nhờ những kiến thức cơ bản này, mình cảm thấy tự tin hơn khi làm việc hoặc nói chuyện về database.
Tất nhiên vẫn còn quá nhiều thứ để tìm hiểu. Database là một lĩnh vực rộng lớn, nhưng mình cũng đã chập chững bắt đầu đi những bước chân đầu tiên (haha, tưởng 10 năm kinh nghiệm thế nào
).
Mình cũng đã refactor kha khá cơ sở dữ liệu của công ty hiện tại: thêm những index thiếu, loại bỏ những index thừa hoặc không hiệu quả (dù sao quá nhiều index cũng không tốt).
Nhưng cái mình nhận được thì còn lớn hơn thế, mình trả lời được những câu hỏi mà trước đây mình vẫn mù mờ, và hiểu được bản chất hơn nhiều so với mấy cái tip trick mà mình sẽ quên ngay sau khi đọc.
Kết
Những thứ gì đi từ cơ bản đều rất tuyệt vời. Nó giúp mình hiểu rõ mình đang muốn gì, làm gì và trả lời được những câu hỏi “tại sao”.
Database rất thú vị, và mình cũng muốn tiếp tục khám phá thêm những điểm thú vị đó trong tương lai 😉
Bài viết này cũng được mình dịch sang tiếng Anh trên blog substack của mình.
Mình viết lại những điều này như một cách để ghi nhớ hành trình làm nghề của mình. Nếu bạn cũng đang làm backend, devops hoặc cloud, hy vọng những chia sẻ này có thể giúp bạn một chút gì đó. Còn nếu có chỗ nào mình hiểu chưa đúng, mình vẫn luôn sẵn sàng học thêm.
All rights reserved