Cả hai giải pháp được đề xuất đều không phải là tối ưu, NHƯNG giải pháp 1 là KHÔNG THỂ THIẾU và do đó HIỆN TẠI!
Một trong những điều đầu tiên bạn học được khi xử lý cơ sở dữ liệu lớn là 'cách tốt nhất' để thực hiện truy vấn thường phụ thuộc vào các yếu tố (được gọi là siêu dữ liệu) trong cơ sở dữ liệu:
- Có bao nhiêu hàng.
- Bạn đang truy vấn bao nhiêu bảng.
- Kích thước của mỗi hàng.
Bởi vì điều này, không có khả năng có một giải pháp viên đạn bạc cho vấn đề của bạn. Cơ sở dữ liệu của bạn không giống với cơ sở dữ liệu của tôi, bạn sẽ cần đánh giá các tối ưu hóa khác nhau nếu bạn cần hiệu suất tốt nhất hiện có.
Bạn có thể sẽ thấy rằng áp dụng và tạo chỉ mục chính xác (và hiểu được cách triển khai gốc của các chỉ mục trong MySQL) trong cơ sở dữ liệu của bạn sẽ giúp ích được nhiều hơn cho bạn.
Có một số quy tắc vàng với các truy vấn hiếm khi bị phá vỡ:
- Không thực hiện chúng trong cấu trúc vòng lặp . Như thường lệ, chi phí tạo kết nối, thực hiện truy vấn và nhận phản hồi rất cao.
- Tránh
SELECT *
trừ khi cần thiết . Việc chọn nhiều cột hơn sẽ làm tăng đáng kể chi phí hoạt động SQL của bạn. - Biết các chỉ mục của bạn . Sử dụng
EXPLAIN
để bạn có thể xem chỉ mục nào đang được sử dụng, tối ưu hóa các truy vấn của bạn để sử dụng những thứ có sẵn và tạo những chỉ mục mới.
Vì lý do này, tôi sẽ thực hiện truy vấn thứ hai (thay thế SELECT *
chỉ với các cột bạn muốn), nhưng có lẽ có nhiều cách tốt hơn để cấu trúc truy vấn nếu bạn có thời gian để tối ưu hóa.
Tuy nhiên, tốc độ không nên KHÔNG là sự cân nhắc duy nhất của bạn về vấn đề này, có một lý do TUYỆT VỜI để không sử dụng gợi ý một:
ƯU TIÊN:tại sao khóa đọc là một điều tốt
Một trong những câu trả lời khác gợi ý rằng việc khóa bảng trong một thời gian dài là một điều xấu và do đó giải pháp nhiều truy vấn là tốt.
Tôi sẽ tranh luận rằng điều này không thể xa sự thật hơn . Trên thực tế, tôi tranh luận rằng trong nhiều trường hợp, khả năng dự đoán của việc chạy một khóa SELECT
truy vấn là một đối số lớn hơn CHO việc chạy truy vấn đó hơn là lợi ích về tối ưu hóa và tốc độ.
Trước hết, khi chúng tôi chạy SELECT
(chỉ đọc) truy vấn trên cơ sở dữ liệu MyISAM hoặc InnoDB (hệ thống mặc định cho MySQL), điều xảy ra là bảng bị khóa đọc. Điều này ngăn không cho bất kỳ thao tác WRITE nào xảy ra trên bảng cho đến khi khóa đọc được trả lại (hoặc SELECT
của chúng tôi truy vấn hoàn thành hoặc không thành công). SELECT
khác các truy vấn không bị ảnh hưởng, vì vậy nếu bạn đang chạy một ứng dụng đa luồng, chúng sẽ tiếp tục hoạt động.
Sự chậm trễ này là một điều TỐT. Tại sao, bạn có thể hỏi? Tính toàn vẹn của dữ liệu quan hệ.
Hãy lấy một ví dụ:chúng tôi đang chạy một hoạt động để lấy danh sách các vật phẩm hiện có trong kho của một nhóm người dùng trên một trò chơi, vì vậy chúng tôi thực hiện điều này tham gia:
SELECT * FROM `users` JOIN `items` ON `users`.`id`=`items`.`inventory_id` WHERE `users`.`logged_in` = 1;
Điều gì sẽ xảy ra nếu, trong hoạt động truy vấn này, một người dùng giao dịch một mặt hàng cho một người dùng khác? Sử dụng truy vấn này, chúng tôi thấy trạng thái trò chơi giống như khi chúng tôi bắt đầu truy vấn:vật phẩm tồn tại một lần, trong kho của người dùng đã có nó trước khi chúng tôi chạy truy vấn.
Nhưng, điều gì sẽ xảy ra nếu chúng ta đang chạy nó trong một vòng lặp?
Tùy thuộc vào việc người dùng giao dịch nó trước hay sau khi chúng tôi đọc thông tin chi tiết của họ và chúng tôi đọc kho của hai người chơi theo thứ tự nào, có bốn khả năng:
- Mặt hàng có thể được hiển thị trong khoảng không quảng cáo của người dùng đầu tiên (quét người dùng B -> quét người dùng A -> mặt hàng được giao dịch HOẶC quét người dùng B -> quét người dùng A -> mặt hàng được giao dịch).
- Mặt hàng có thể được hiển thị trong khoảng không quảng cáo của người dùng thứ hai (mặt hàng được giao dịch -> quét người dùng A -> quét người dùng B HOẶC mặt hàng được giao dịch -> quét người dùng B -> quét người dùng A).
- Mục có thể được hiển thị trong cả hai khoảng không quảng cáo (quét người dùng A -> mặt hàng được giao dịch -> quét người dùng B).
- Mục này có thể được hiển thị bằng không trong tổng số hàng tồn kho của người dùng (quét người dùng B -> mặt hàng được giao dịch -> quét người dùng A).
Điều này có nghĩa là chúng tôi sẽ không thể dự đoán kết quả của truy vấn hoặc để đảm bảo tính toàn vẹn của mối quan hệ .
Nếu bạn định đưa 5.000 đô la cho anh chàng có ID 1000000 vào nửa đêm Thứ Ba, tôi hy vọng bạn có trong tay 10k đô la. Nếu chương trình của bạn dựa vào các mục duy nhất là duy nhất khi ảnh chụp nhanh được chụp, bạn có thể sẽ đưa ra một ngoại lệ với loại truy vấn này.
Khóa tốt vì nó tăng khả năng dự đoán và bảo vệ tính toàn vẹn trong tổng số kết quả.
Lưu ý:Bạn có thể buộc khóa vòng lặp bằng giao dịch , nhưng nó sẽ vẫn chậm hơn.
Ồ và cuối cùng, SỬ DỤNG BÁO CÁO ĐÃ CHUẨN BỊ!
Bạn không bao giờ nên có một câu lệnh giống như sau:
mysqli_query("SELECT * FROM Table2 WHERE ColumnAId=" . $row['ColumnAId'], $con);
mysqli
có hỗ trợ cho các báo cáo đã chuẩn bị sẵn
. Đọc về chúng và sử dụng chúng, chúng sẽ giúp bạn tránh điều gì đó khủng khiếp đang xảy ra với cơ sở dữ liệu của bạn
.