Có phải tốt hơn để tách một truy vấn lớn thành nhiều truy vấn nhỏ hơn?


13

Có những tình huống đòi hỏi phải có truy vấn thực sự lớn, kết hợp nhiều bảng cùng với các câu lệnh chọn phụ trong đó để tạo ra kết quả mong muốn.

Câu hỏi của tôi là, chúng ta có nên xem xét sử dụng nhiều truy vấn nhỏ hơn và đưa các hoạt động logic vào lớp ứng dụng bằng cách truy vấn DB trong nhiều cuộc gọi hay tốt hơn là nên thực hiện tất cả chúng trong một lần?
Ví dụ, hãy xem xét các truy vấn sau:

SELECT *
FROM   `users`
WHERE  `user_id` IN (SELECT f2.`friend_user_id`
                     FROM   `friends` AS f1
                            INNER JOIN `friends` AS f2
                              ON f1.`friend_user_id` = f2.`user_id`
                     WHERE  f2.`is_page` = 0
                            AND f1.`user_id` = "%1$d"
                            AND f2.`friend_user_id` != "%1$d"
                            AND f2.`friend_user_id` NOT IN (SELECT `friend_user_id`
                                                            FROM   `friends`
                                                            WHERE  `user_id` = "%1$d"))
       AND `user_id` NOT IN (SELECT `user_id`
                             FROM   `friend_requests`
                             WHERE  `friend_user_id` = "%1$d")
       AND `user_image` IS NOT NULL
ORDER  BY RAND() 
LIMIT %2$d

Cách tốt nhất để làm điều đó là gì?

Câu trả lời:


14

Tôi sẽ không đồng ý với các truy vấn lớn và phức tạp với datagod ở đây. Tôi thấy đây chỉ là những vấn đề nếu chúng vô tổ chức. Hiệu suất-khôn ngoan, những điều này hầu như luôn luôn tốt hơn bởi vì người lập kế hoạch có nhiều tự do hơn trong cách lấy về thông tin. Tuy nhiên, các truy vấn lớn cần phải được viết với khả năng duy trì trong tâm trí. Nói chung, tôi đã thấy rằng SQL đơn giản, có cấu trúc tốt để dễ gỡ lỗi ngay cả khi một truy vấn duy nhất tiếp tục cho hơn 200 dòng. Điều này là do thông thường bạn có một ý tưởng khá tốt về loại vấn đề bạn đang giải quyết nên chỉ có một vài lĩnh vực trong truy vấn mà bạn phải kiểm tra.

Các vấn đề bảo trì, IME, xuất hiện khi cấu trúc của SQL bị hỏng. Các truy vấn dài, phức tạp trong các mục chọn lọc làm suy yếu khả năng đọc và xử lý sự cố, cũng như các chế độ xem nội tuyến và cả hai truy vấn này nên được tránh trong các truy vấn dài. Thay vào đó, hãy sử dụng VIEWs nếu bạn có thể (lưu ý nếu bạn đang sử dụng MySQL, các chế độ xem không thực hiện tốt tất cả, nhưng trên hầu hết các db khác họ làm) và sử dụng các biểu thức bảng phổ biến khi chúng không hoạt động (MySQL không hỗ trợ các biểu thức này btw).

Các truy vấn phức tạp dài hoạt động khá tốt cả từ trường hợp khả năng duy trì và hiệu suất khi bạn giữ các mệnh đề đơn giản và nơi bạn làm nhiều nhất có thể với các phép nối thay vì chọn phụ. Mục tiêu là làm cho nó sao cho "các bản ghi không hiển thị" cung cấp cho bạn một vài vị trí rất cụ thể trong truy vấn để kiểm tra (nó có bị bỏ trong một liên kết hoặc được lọc ra trong mệnh đề where không?) Và vì vậy nhóm bảo trì thực sự có thể duy trì mọi thứ.

Về khả năng mở rộng, hãy nhớ rằng trình hoạch định càng linh hoạt, đó cũng là một điều tốt ....

Chỉnh sửa: Bạn đề cập đây là MySQL, do đó, các chế độ xem không thể thực hiện tốt điều đó và CTE không còn là vấn đề nữa. Ngoài ra, ví dụ đưa ra không đặc biệt dài hay phức tạp nên không có vấn đề gì.


Lưu ý: Tôi đã có các truy vấn (không phải trong MySQL, nhưng vẫn ...) đủ dài và phức tạp để các kế hoạch truy vấn được tạo không tối ưu. Trong những trường hợp này, bạn thực sự có thể nhận được kết quả nhanh hơn, phá vỡ một truy vấn cực kỳ phức tạp thành hai truy vấn ít phức tạp hơn. Điều đó nói rằng, nó rất hiếm và nói chung tôi sẽ viết truy vấn phức tạp và tìm hiểu xem có vấn đề gì không thay vì chia truy vấn thành các phần nhỏ hơn trước.
RDFozz

8

Là một người phải hỗ trợ / dọn dẹp các truy vấn lớn và phức tạp này, tôi sẽ nói rằng tốt hơn hết là chia chúng thành nhiều phần nhỏ dễ hiểu. Nó không nhất thiết phải tốt hơn từ quan điểm hiệu suất, nhưng ít nhất bạn đang cho SQL cơ hội tốt hơn để đưa ra một kế hoạch truy vấn tốt.

Làm cho cuộc sống dễ dàng hơn với những người theo dõi bạn, và họ sẽ nói những điều tốt đẹp về bạn. Làm khó họ và họ sẽ nguyền rủa bạn.


2
Tuy nhiên, nhược điểm của một chuỗi các truy vấn đơn giản là trạng thái thay đổi đáng kể trên chúng, làm cho việc gỡ lỗi tổng thể của ứng dụng trở nên phức tạp hơn. Tức là bạn có thể gỡ lỗi các truy vấn SQL lớn thường xuyên dưới dạng cây nhưng mã ứng dụng sẽ nhận được câu lệnh gỡ lỗi bằng cách kiểm tra trạng thái thay đổi trong các câu lệnh. Các vấn đề thực sự liên quan đến thực tế là các lựa chọn phụ và chế độ xem nội tuyến cũng là cây của riêng họ .....
Chris Travers

Trong trường hợp của tôi, người duy nhất phải quản lý DB và mã là chính tôi. Và chủ yếu là câu hỏi của tôi là về hiệu suất điểm truy vấn.
Hamed Momeni

Các bạn sẽ phải xem cách tôi viết các quy trình hàng loạt lớn của tôi. Chia nhỏ mọi thứ thành các truy vấn đơn giản, rất dễ đọc. Tôi thiên vị bởi vì các truy vấn cuối cùng tôi cố gắng dọn dẹp thường xuyên dài hơn 1000 dòng.
datagod

5

2 xu của tôi cho 2 từ khóa hiệu suất truy vấn và khả năng mở rộng:

Hiệu suất truy vấn: Tính song song của SQL Server đã thực hiện rất tốt việc chia nhỏ các truy vấn thành các tìm kiếm đa luồng, vì vậy tôi không chắc sẽ cải thiện hiệu suất truy vấn bằng cách nào cho SQL Server. Bạn sẽ phải xem xét kế hoạch thực hiện để xem mức độ song song bạn nhận được khi thực hiện nó và so sánh kết quả theo cả hai cách. Nếu cuối cùng bạn phải sử dụng một gợi ý truy vấn để có được hiệu suất tương đương hoặc tốt hơn, thì IMO không có giá trị vì gợi ý truy vấn có thể không tối ưu sau này.

Khả năng mở rộng: Đọc các truy vấn có thể dễ dàng hơn như datagod đã nêu và chia nó thành các truy vấn riêng biệt có ý nghĩa nếu bạn cũng có thể sử dụng các truy vấn mới của mình trong các lĩnh vực khác, nhưng nếu bạn cũng sẽ không sử dụng chúng cho các cuộc gọi khác nó sẽ còn được lưu trữ nhiều hơn nữa để quản lý cho 1 tác vụ và IMO sẽ không đóng góp bất kỳ khả năng mở rộng nào.


2
RE: Tham chiếu "Máy chủ SQL" mặc dù OP không chỉ định bất kỳ RDBMS cụ thể nào. Tôi nghi ngờ họ đang ở trên MySQL từ các dấu tích phía sau vàLIMIT
Martin Smith

@MartinSmith Bạn nghi ngờ chính xác. Đó là MySQL.
Hamed Momeni

2

Đôi khi, không có lựa chọn nào khác ngoài việc chia truy vấn lớn / phức tạp thành các truy vấn nhỏ. Cách tốt nhất để xác định điều đó sẽ là sử dụng EXPLAINcâu lệnh với SELECTcâu lệnh. Số lượng dấu vết / lần quét mà db của bạn sẽ thực hiện để tìm nạp dữ liệu của bạn là sản phẩm của các giá trị "hàng" được trả về bởi EXPLAINtruy vấn của bạn . Trong trường hợp của chúng tôi, chúng tôi đã có một truy vấn tham gia 10 bảng. Đối với bản ghi cụ thể, dấu vết lên tới 409M đã viết blog DB của chúng tôi và đẩy mức sử dụng CPU của máy chủ DB của chúng tôi lên hơn 300%. Chúng tôi có thể truy xuất thông tin tương tự bằng cách chia các truy vấn nhanh hơn nhiều.

Vì vậy, trong ngắn hạn, trong một số trường hợp, việc phân tách một truy vấn phức tạp / lớn có ý nghĩa nhưng trong trường hợp khác, nó có thể dẫn đến nhiều vấn đề về hiệu năng hoặc bảo trì và điều này nên được xử lý theo từng trường hợp cụ thể.

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.