Cái gì nhanh hơn, một truy vấn lớn hay nhiều truy vấn nhỏ?


68

Tôi đã làm việc cho các công ty khác nhau và tôi nhận thấy rằng một số người trong số họ thích có quan điểm sẽ tham gia một bảng với tất cả "người thân" của nó. Nhưng sau đó trên ứng dụng một số lần, chúng ta chỉ cần sử dụng 1 cột.

Vì vậy, sẽ nhanh hơn nếu chỉ thực hiện các lựa chọn đơn giản và sau đó "tham gia" chúng vào mã hệ thống?

Hệ thống có thể là php, java, asp, bất kỳ ngôn ngữ nào kết nối với cơ sở dữ liệu.

Vì vậy, câu hỏi là, cái gì nhanh hơn từ phía Máy chủ (php, java, asp, ruby, python ...) đến cơ sở dữ liệu chạy một truy vấn có được mọi thứ chúng ta cần hoặc đi từ phía máy chủ đến cơ sở dữ liệu và chạy một truy vấn chỉ nhận được các cột từ một bảng tại thời điểm đó?


2
Bạn đang sử dụng triển khai 'SQL' nào? MySQL, Microsoft SQL Server, Oracle, Postgresql, v.v? Vui lòng cập nhật thẻ của bạn.
RLF

1
Mysql và Postgresql
sudo.ie

6
Kinh nghiệm của tôi là MySQL không thích các truy vấn phức tạp và thường nhanh hơn với các truy vấn rất đơn giản (nhưng nhiều hơn). Trình tối ưu hóa truy vấn của Postgres tốt hơn nhiều và ở đó thường hiệu quả hơn khi chạy một truy vấn lớn.
a_horse_with_no_name

3
@a_horse_with_no_name Đó là sự khái quát hóa rất rộng, đặc biệt trong bối cảnh của câu hỏi này. Trình tối ưu hóa MySQL thực sự rất đơn giản bởi thiết kế và có thể gây ra sự cố với các phép nối và truy vấn phụ - đặc biệt là trên các phiên bản cũ hơn của MySQL - có các kế hoạch nhanh hơn trong PostgreQuery, trong khi MySQL có thể rất nhanh cho tải OLTP thuần túy. Tuy nhiên, trong ngữ cảnh của câu hỏi, một truy vấn lớn sẽ nhanh hơn, hãy giả sử - trong trường hợp xấu nhất có thể xảy ra - một CHỌN bên trong một vòng lập trình (bất kể RDBMS được sử dụng).
jynus

2
@jynus: tốt, câu hỏi rất rộng (cộng: Tôi nói "trong kinh nghiệm của tôi" - người khác có thể có những trải nghiệm khác nhau). Một truy vấn bên trong LOOP không bao giờ là một ý tưởng hay và hầu như luôn là kết quả của thiết kế kém hoặc thiếu hiểu biết về cách làm việc với cơ sở dữ liệu quan hệ.
a_horse_with_no_name

Câu trả lời:


69

Điều gì sẽ giải quyết câu hỏi của bạn là chủ đề THAM GIA KHAI THÁC.

Theo trang 209 của cuốn sách

MySQL hiệu suất cao

Bạn có thể phân tách một phép nối bằng cách chạy nhiều truy vấn một bảng thay vì nối nhiều lần, sau đó thực hiện phép nối trong ứng dụng. Ví dụ: thay vì truy vấn này:

SELECT * FROM tag
JOIN tag_post ON tag_post.tag_id = tag.id
JOIN post ON tag_post.post_id = post.id
WHERE tag.tag = 'mysql';

Bạn có thể chạy các truy vấn sau:

SELECT * FROM tag WHERE tag = 'mysql';
SELECT * FROM tag_post WHERE tag_id=1234;
SELECT * FROM post WHERE post.id IN (123,456,567,9098,8904);

Tại sao trên trái đất bạn sẽ làm điều này? Thoạt nhìn có vẻ lãng phí, vì bạn đã tăng số lượng truy vấn mà không nhận được bất cứ điều gì. Tuy nhiên, việc tái cấu trúc như vậy thực sự có thể mang lại lợi thế đáng kể về hiệu suất:

  • Bộ nhớ đệm có thể hiệu quả hơn. Nhiều ứng dụng lưu trữ các "đối tượng" ánh xạ trực tiếp vào các bảng. Trong ví dụ này, nếu đối tượng có thẻ mysqlđã được lưu vào bộ đệm, ứng dụng sẽ bỏ qua truy vấn đầu tiên. Nếu bạn tìm thấy các bài đăng có ID là 123, 567 hoặc 908 trong bộ đệm, bạn có thể xóa chúng khỏi IN()danh sách. Bộ đệm truy vấn cũng có thể được hưởng lợi từ chiến lược này. Nếu chỉ một trong các bảng thay đổi thường xuyên, việc phân tách một phép nối có thể làm giảm số lượng mất hiệu lực của bộ đệm.
  • Thực hiện các truy vấn riêng lẻ đôi khi có thể làm giảm sự tranh chấp khóa
  • Việc tham gia trong ứng dụng giúp dễ dàng mở rộng cơ sở dữ liệu bằng cách đặt các bảng trên các máy chủ khác nhau.
  • Các truy vấn có thể được hiệu quả hơn. Trong ví dụ này, sử dụng IN()danh sách thay vì tham gia cho phép MySQL sắp xếp ID hàng và truy xuất hàng tối ưu hơn mức có thể có với liên kết.
  • Bạn có thể giảm truy cập hàng dự phòng. Tham gia vào ứng dụng có nghĩa là chỉ truy xuất mỗi hàng một lần. Trong khi đó, việc tham gia truy vấn về cơ bản là sự không chuẩn hóa có thể truy cập nhiều lần vào cùng một dữ liệu. Vì lý do tương tự, việc tái cấu trúc như vậy cũng có thể làm giảm tổng lưu lượng mạng và sử dụng bộ nhớ.
  • Ở một mức độ nào đó, bạn có thể xem kỹ thuật này khi thực hiện thủ công hàm băm thay vì thuật toán vòng lặp lồng nhau mà MySQL sử dụng để thực hiện phép nối. Một phép nối băm có thể hiệu quả hơn.

Do đó, các thao tác tham gia trong ứng dụng có thể hiệu quả hơn khi bạn lưu trữ và sử dụng lại nhiều dữ liệu từ các truy vấn trước đó, bạn phân phối dữ liệu trên nhiều máy chủ, bạn thay thế các liên kết bằng IN()danh sách hoặc liên kết tham chiếu đến cùng một bảng nhiều lần.

QUAN SÁT

Tôi thích dấu đầu dòng đầu tiên vì InnoDB hơi nặng tay khi kiểm tra chéo bộ đệm truy vấn.

Đối với gạch đầu dòng cuối cùng, tôi đã viết một bài đăng lại vào ngày 11 tháng 3 năm 2013 ( Có sự khác biệt thực thi giữa điều kiện THAM GIA và điều kiện WHERE không? ) Mô tả thuật toán vòng lặp lồng nhau. Sau khi đọc nó, bạn sẽ thấy sự phân rã tham gia tốt như thế nào.

Đối với tất cả các điểm khác từ cuốn sách , các nhà phát triển thực sự tìm kiếm hiệu suất là điểm mấu chốt. Một số người dựa vào các phương tiện bên ngoài (bên ngoài ứng dụng) để cải tiến hiệu suất như sử dụng đĩa nhanh, nhận thêm CPU / lõi, điều chỉnh công cụ lưu trữ và điều chỉnh tệp cấu hình. Những người khác sẽ khóa xuống và viết mã tốt hơn. Một số người có thể sử dụng mã hóa tất cả các thông tin nghiệp vụ trong Thủ tục lưu trữ nhưng vẫn không áp dụng phân tách tham gia (Xem các đối số chống lại hoặc để đưa logic ứng dụng vào lớp cơ sở dữ liệu cùng với các bài đăng khác). Tất cả tùy thuộc vào văn hóa và khả năng chịu đựng của mỗi cửa hàng phát triển.

Một số có thể hài lòng với hiệu suất và không chạm vào mã nữa. Khác đơn giản là không nhận ra có những lợi ích tuyệt vời mà người ta có thể gặt hái nếu họ thử tham gia sáng tác.

Đối với những nhà phát triển sẵn sàng ...

HÃY THỬ MỘT LẦN !!!


3
Đối với liên kết đó về việc thay đổi thành 3 truy vấn ... Tôi biết và tôn trọng Baron, Vadim và Peter, nhưng tôi không đồng ý với đề xuất sai lệch này. Hầu hết các cuộc tranh luận ủng hộ việc chia tay là rất hiếm khi không đáng để đề cập. Tiếp tục với một truy vấn duy nhất với THAM GIA, sau đó hãy cải thiện nó.
Rick James

2
@RickJames Tôi đồng ý với tinh thần bình luận của bạn. Trong những năm qua, tôi đã thấy công việc phân rã tham gia cho một số và thất bại cho những người khác. Ngay cả với bộ kỹ năng SQL thích hợp, nó có thể chống lại bạn nếu việc phân tách tham gia không được thực hiện đúng. Tại nhà tuyển dụng hiện tại của tôi, nhiều người yêu thích mở rộng quy mô, đặc biệt là khi mã kế thừa có liên quan và có sẵn túi sâu. Với những người có hương vị trứng cá muối nhưng ngân sách salad trứng, tham gia phân hủy có thể có giá trị rủi ro nhưng phải được thực hiện ngay.
RolandoMySQLDBA

Tôi rất muốn xem làm thế nào điều này hoạt động trong môi trường Oracle nếu tôi có quyền và thời gian.
Rick Henderson

Một cách khác có thể nhanh hơn là nếu bạn đang thực hiện đặt hàng, sẽ ít tính toán tổng thể để đặt hàng danh sách nhỏ hơn so với đặt hàng một danh sách lớn.
Evan Siroky

24

Trong Postgres (và có thể là bất kỳ RDBMS nào ở mức độ tương tự, MySQL ở mức độ thấp hơn), ít truy vấn hơn hầu như luôn luôn nhanh hơn nhiều .

Chi phí phân tích cú pháp và lập kế hoạch nhiều truy vấn đã nhiều hơn bất kỳ lợi ích nào có thể có trong hầu hết các trường hợp.

Không nói về công việc bổ sung sẽ được thực hiện trong máy khách, kết hợp các kết quả, thường chậm hơn nhiều . Một RDBMS chuyên về loại nhiệm vụ và hoạt động đó dựa trên các loại dữ liệu gốc. Không truyền tới textvà quay lại các kết quả trung gian hoặc chuyển đổi sang các kiểu máy khách gốc, điều này thậm chí có thể dẫn đến kết quả ít chính xác hơn (hoặc không chính xác!). Hãy nghĩ về số dấu phẩy động ...

Bạn cũng chuyển nhiều dữ liệu hơn giữa máy chủ DB và máy khách. Điều này có thể không đáng kể cho một bàn tay đầy giá trị, hoặc tạo ra một sự khác biệt lớn.

Nếu nhiều truy vấn có nghĩa là nhiều chuyến đi khứ hồi đến máy chủ cơ sở dữ liệu, bạn cũng thu thập nhiều lần độ trễ của mạng và chi phí giao dịch, thậm chí có thể cả chi phí kết nối. Lớn, mất lớn.

Tùy thuộc vào thiết lập của bạn, độ trễ mạng một mình có thể mất nhiều thời gian hơn tất cả các phần còn lại theo đơn đặt hàng cường độ.

Câu hỏi liên quan về SO:

Có thể có một bước ngoặt cho rất lớn , truy vấn chạy dài vì các giao dịch thu thập ổ khóa trên DB hàng trên đường đi. Các truy vấn rất lớn có thể giữ nhiều khóa trong một khoảng thời gian dài có thể gây ra ma sát với các truy vấn đồng thời .


Chỉ vì tò mò, bạn nghĩ gì rất lớn ?
Sablefoste

@Sablefoste: Rất nhiều phụ thuộc vào mẫu truy cập của bạn. Một điểm quan trọng là nơi các giao dịch đồng thời bắt đầu xếp hàng, chờ khóa được phát hành. Hoặc nếu bạn tích lũy đủ khóa để ăn một phần đáng kể tài nguyên của bạn. Hoặc nếu các truy vấn của bạn chạy đủ lâu để can thiệp vào autovacuum ...
Erwin Brandstetter

Nhưng nếu chúng ta có một tình huống hơi điển hình - một truy vấn sử dụng phép nối ngoài và trả về nhiều dữ liệu dư thừa cho bảng "cha mẹ", thì sau đó phải được phân tích và sắp xếp bởi ứng dụng (rất có thể, một số thư viện ORM) so với chọn nhỏ mà tìm nạp tất cả các ID cần thiết trước rồi sau đó chọn nhỏ hơn bằng IN () thay vì nối ngoài? Cách tiếp cận thứ hai sẽ hiệu quả hơn (xem xét cả DB và ứng dụng tiêu thụ CPU và băng thông truyền thông)?
JustAMartin

1
@JustAMartin: Nghe có vẻ giống như loại truy vấn gần như chắc chắn nhanh hơn khi được xử lý bởi trình hoạch định truy vấn của RDBMS - giả sử các truy vấn chính xác. Liên quan returns lots of redundant data for "parent" table: Tại sao bạn sẽ trả lại dữ liệu dư thừa? Chỉ trả lại dữ liệu bạn cần.
Erwin Brandstetter

1
Với RDBMS tham gia bên ngoài trả về dữ liệu từ bảng cha được nhân đôi cho mỗi đứa trẻ được tham gia, có nghĩa là một số chi phí mạng và bộ nhớ, sau đó một số phân tích bổ sung trong công cụ ORM để loại bỏ các giá trị cha mẹ trùng lặp và chỉ giữ một cha mẹ với n con. Vì vậy, với một truy vấn duy nhất, chúng tôi tiết kiệm được công việc hiệu quả của trình lập kế hoạch truy vấn RDBMS, ít yêu cầu mạng (hoặc đường ống cục bộ) hơn nhưng lại mất thêm tải trọng không cần thiết và dịch chuyển dữ liệu xung quanh trong thư viện ORM. Tôi đoán, nó như mọi khi - đo trước khi tối ưu hóa.
JustAMartin
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.