Là các truy vấn cá nhân nhanh hơn tham gia?


44

Câu hỏi về khái niệm: Các truy vấn cá nhân có nhanh hơn tham gia không, hoặc: Tôi có nên cố gắng ép mọi thông tin tôi muốn ở phía máy khách vào một câu lệnh CHỌN hay chỉ sử dụng nhiều như có vẻ thuận tiện?

TL; DR : Nếu truy vấn đã tham gia của tôi mất nhiều thời gian hơn so với chạy các truy vấn riêng lẻ, đây có phải là lỗi của tôi không hoặc đây có phải là dự kiến ​​không?

Đầu tiên, tôi không rành về cơ sở dữ liệu, nên có thể chỉ là tôi, nhưng tôi nhận thấy rằng khi tôi phải lấy thông tin từ nhiều bảng, thì "thường" nhanh hơn để có được thông tin này qua nhiều truy vấn trên các bảng riêng lẻ (có thể chứa một phép nối bên trong đơn giản) và vá dữ liệu lại với nhau ở phía máy khách để cố gắng viết một truy vấn đã tham gia (phức tạp) trong đó tôi có thể nhận được tất cả dữ liệu trong một truy vấn.

Tôi đã cố gắng kết hợp một ví dụ cực kỳ đơn giản:

Câu đố SQL

Cài đặt lược đồ :

CREATE TABLE MASTER 
( ID INT NOT NULL
, NAME VARCHAR2(42 CHAR) NOT NULL
, CONSTRAINT PK_MASTER PRIMARY KEY (ID)
);

CREATE TABLE DATA
( ID INT NOT NULL
, MASTER_ID INT NOT NULL
, VALUE NUMBER
, CONSTRAINT PK_DATA PRIMARY KEY (ID)
, CONSTRAINT FK_DATA_MASTER FOREIGN KEY (MASTER_ID) REFERENCES MASTER (ID)
);

INSERT INTO MASTER values (1, 'One');
INSERT INTO MASTER values (2, 'Two');
INSERT INTO MASTER values (3, 'Three');

CREATE SEQUENCE SEQ_DATA_ID;

INSERT INTO DATA values (SEQ_DATA_ID.NEXTVAL, 1, 1.3);
INSERT INTO DATA values (SEQ_DATA_ID.NEXTVAL, 1, 1.5);
INSERT INTO DATA values (SEQ_DATA_ID.NEXTVAL, 1, 1.7);
INSERT INTO DATA values (SEQ_DATA_ID.NEXTVAL, 2, 2.3);
INSERT INTO DATA values (SEQ_DATA_ID.NEXTVAL, 3, 3.14);
INSERT INTO DATA values (SEQ_DATA_ID.NEXTVAL, 3, 3.7);

Truy vấn A :

select NAME from MASTER
where ID = 1

Kết quả :

| NAME |
--------
|  One |

Truy vấn B :

select ID, VALUE from DATA
where MASTER_ID = 1

Kết quả :

| ID | VALUE |
--------------
|  1 |   1.3 |
|  2 |   1.5 |
|  3 |   1.7 |

Truy vấn C :

select M.NAME, D.ID, D.VALUE 
from MASTER M INNER JOIN DATA D ON M.ID=D.MASTER_ID
where M.ID = 1

Kết quả :

| NAME | ID | VALUE |
---------------------
|  One |  1 |   1.3 |
|  One |  2 |   1.5 |
|  One |  3 |   1.7 |

Tất nhiên, tôi không đo bất kỳ hiệu suất nào với những thứ này, nhưng người ta có thể quan sát:

  • Truy vấn A + B trả về cùng một lượng thông tin có thể sử dụng như Truy vấn C.
  • A + B phải trả lại 1 + 2x3 == 7 "Ô dữ liệu" cho máy khách
  • C phải trả lại 3x3 == 9 "Ô dữ liệu" cho máy khách, vì với phép nối, tôi tự nhiên bao gồm một số dự phòng trong tập kết quả.

Tổng quát hóa từ điều này (càng xa càng tốt):

Một truy vấn đã tham gia luôn phải trả về nhiều dữ liệu hơn các truy vấn riêng lẻ nhận cùng một lượng thông tin. Do cơ sở dữ liệu phải kết hợp dữ liệu với nhau, nên đối với các bộ dữ liệu lớn, người ta có thể giả định rằng cơ sở dữ liệu phải thực hiện nhiều công việc hơn trên một truy vấn đã tham gia so với các truy vấn riêng lẻ, vì (ít nhất) nó phải trả lại nhiều dữ liệu hơn cho máy khách.

Liệu nó có tuân theo điều này không, khi tôi quan sát rằng việc tách một truy vấn phía máy khách thành nhiều truy vấn mang lại hiệu suất tốt hơn, đây chỉ là cách để đi, hay nó có nghĩa là tôi đã làm rối tung truy vấn đã tham gia?


Bình luận không dành cho thảo luận mở rộng; cuộc trò chuyện này đã được chuyển sang trò chuyện .
Jack Douglas

1
Tôi đã chạy một điểm chuẩn và đăng kết quả trong một bài viết trên Medium . Tôi đã có thể thêm một câu trả lời ở đây, nhưng đã làm nó trên một câu hỏi khác , và đăng cùng một câu trả lời cho nhiều câu hỏi được tán thành .
Benjamin

Câu trả lời:


45

Là các truy vấn riêng lẻ nhanh hơn tham gia, hoặc: Tôi có nên cố gắng ép mọi thông tin tôi muốn ở phía máy khách vào một câu lệnh CHỌN hay chỉ sử dụng nhiều như có vẻ thuận tiện?

Trong bất kỳ kịch bản hiệu suất nào, bạn phải kiểm tra và đo lường các giải pháp để xem cái nào nhanh hơn .

Điều đó nói rằng, hầu như luôn luôn là trường hợp kết quả được tham gia từ cơ sở dữ liệu được điều chỉnh đúng sẽ nhanh hơn và mở rộng quy mô tốt hơn là trả lại các hàng nguồn cho máy khách và sau đó nối chúng ở đó. Cụ thể, nếu các bộ đầu vào lớn và tập kết quả nhỏ - hãy nghĩ về truy vấn sau trong ngữ cảnh của cả hai chiến lược: nối hai bảng có nhau 5 GB, với một tập kết quả là 100 hàng. Đó là một cực đoan, nhưng bạn thấy quan điểm của tôi.

Tôi đã nhận thấy rằng khi tôi phải lấy thông tin từ nhiều bảng, việc lấy thông tin này thông qua nhiều truy vấn trên các bảng riêng lẻ (có thể chứa một liên kết bên trong đơn giản) và vá dữ liệu với nhau ở phía máy khách để thử để viết một truy vấn (phức tạp) đã tham gia, nơi tôi có thể nhận được tất cả dữ liệu trong một truy vấn.

Rất có khả năng lược đồ cơ sở dữ liệu hoặc các chỉ mục có thể được cải thiện để phục vụ tốt hơn các truy vấn bạn đang sử dụng.

Một truy vấn đã tham gia luôn phải trả về nhiều dữ liệu hơn các truy vấn riêng lẻ nhận cùng một lượng thông tin.

Thông thường đây không phải là trường hợp. Hầu hết thời gian ngay cả khi các bộ đầu vào lớn, tập kết quả sẽ nhỏ hơn nhiều so với tổng của các đầu vào.

Tùy thuộc vào ứng dụng, các tập kết quả truy vấn rất lớn được trả về cho máy khách là một cờ đỏ ngay lập tức: ứng dụng khách đang làm gì với một tập hợp dữ liệu lớn như vậy mà không thể được thực hiện gần hơn với cơ sở dữ liệu? Hiển thị 1.000.000 hàng cho người dùng rất đáng nghi ngờ. Băng thông mạng cũng là một nguồn tài nguyên hữu hạn.

Do cơ sở dữ liệu phải kết hợp dữ liệu với nhau, nên đối với các bộ dữ liệu lớn, người ta có thể giả định rằng cơ sở dữ liệu phải thực hiện nhiều công việc hơn trên một truy vấn đã tham gia so với các truy vấn riêng lẻ, vì (ít nhất) nó phải trả lại nhiều dữ liệu hơn cho máy khách.

Không cần thiết. Nếu dữ liệu được lập chỉ mục chính xác, hoạt động nối có nhiều khả năng được thực hiện hiệu quả hơn tại cơ sở dữ liệu mà không cần phải quét một lượng lớn dữ liệu. Hơn nữa, các công cụ cơ sở dữ liệu quan hệ được tối ưu hóa đặc biệt ở mức độ thấp để tham gia ; ngăn xếp khách hàng không.

Liệu nó có tuân theo điều này không, khi tôi quan sát rằng việc tách một truy vấn phía máy khách thành nhiều truy vấn mang lại hiệu suất tốt hơn, đây chỉ là cách để đi, hay nó có nghĩa là tôi đã làm rối tung truy vấn đã tham gia?

Vì bạn nói rằng bạn thiếu kinh nghiệm khi nói đến cơ sở dữ liệu, tôi sẽ khuyên bạn nên tìm hiểu thêm về thiết kế cơ sở dữ liệu và điều chỉnh hiệu suất. Tôi khá chắc chắn rằng vấn đề nằm ở đây. Các truy vấn SQL được viết không hiệu quả cũng có thể, nhưng với một lược đồ đơn giản ít có khả năng là một vấn đề.

Bây giờ, điều đó không có nghĩa là không có cách nào khác để cải thiện hiệu suất. Có những kịch bản mà bạn có thể chọn để quét một tập hợp dữ liệu từ trung bình đến lớn và trả lại cho khách hàng nếu có ý định sử dụng một số loại cơ chế lưu trữ. Bộ nhớ đệm có thể là tuyệt vời, nhưng nó giới thiệu sự phức tạp trong thiết kế của bạn. Bộ nhớ đệm thậm chí có thể không thích hợp cho ứng dụng của bạn.

Một điều chưa được đề cập ở bất cứ đâu là duy trì tính nhất quán trong dữ liệu được trả về từ cơ sở dữ liệu. Nếu các truy vấn riêng biệt được sử dụng, nhiều khả năng (do nhiều yếu tố) có dữ liệu không nhất quán được trả về, trừ khi sử dụng một hình thức cách ly ảnh chụp nhanh cho mỗi bộ truy vấn.


+1 cho băng thông mạng cũng là một tài nguyên hữu hạn.
Hari Harker

OP đang nói rằng các tập kết quả dữ liệu THAM GIA luôn lớn hơn. > Một truy vấn đã tham gia luôn phải trả về nhiều dữ liệu hơn các truy vấn riêng lẻ. Tôi nghĩ rằng điều này là đúng khách quan (cho> =), ví dụ: tập kết quả khác nhau về kích thước, do đó, nhiều dữ liệu hơn trên dây. Bạn có một ví dụ mà điều này không đúng? Nếu tôi tham gia Tác giả -> Bài đăng và Tác giả có một trường gọi là "tiểu sử" là trường JSON 1MB, đối với Tác giả của 100 Bài đăng, qua dây tôi sẽ truyền 100MB so với 1MB. Điều này có sai không?
hytromo

6

Tất nhiên, tôi đã không đo bất kỳ hiệu suất với những

Bạn kết hợp một số mã mẫu tốt. Bạn đã xem xét thời gian trong SQL Fiddle chưa? Ngay cả một số thử nghiệm hiệu suất không khoa học ngắn gọn sẽ cho thấy rằng truy vấn ba trong phần trình diễn của bạn mất khoảng thời gian tương tự để chạy như một hoặc hai truy vấn riêng biệt. Kết hợp một và hai mất khoảng gấp đôi thời gian ba và đó là trước khi bất kỳ tham gia phía khách hàng nào được thực hiện.

Khi bạn tăng dữ liệu, tốc độ truy vấn một và hai sẽ phân kỳ, nhưng việc nối cơ sở dữ liệu vẫn sẽ nhanh hơn.

Bạn cũng nên xem xét những gì sẽ xảy ra nếu tham gia bên trong đang loại bỏ dữ liệu.


2

Trình tối ưu hóa truy vấn cũng nên được xem xét. Vai trò của nó là lấy SQL khai báo của bạn và dịch nó thành các bước thủ tục. Để tìm ra sự kết hợp hiệu quả nhất của các bước thủ tục, nó sẽ kiểm tra các kết hợp sử dụng chỉ mục, sắp xếp, bộ kết quả trung gian bộ đệm và tất cả các loại khác. Số lượng hoán vị có thể cực kỳ lớn ngay cả với những truy vấn trông khá đơn giản.

Phần lớn tính toán được thực hiện để tìm ra kế hoạch tốt nhất được thúc đẩy bởi sự phân phối dữ liệu trong các bảng. Các bản phân phối này được lấy mẫu và lưu trữ dưới dạng đối tượng thống kê. Nếu những điều này là sai, họ dẫn người tối ưu hóa để đưa ra lựa chọn kém. Những lựa chọn tồi trong kế hoạch sớm dẫn đến những lựa chọn thậm chí còn kém hơn về sau trong hiệu ứng quả cầu tuyết.

Không có gì lạ đối với một truy vấn có kích thước trung bình trả về lượng dữ liệu khiêm tốn để mất vài phút để chạy. Lập chỉ mục chính xác và thống kê tốt sau đó giảm điều này xuống còn mili giây.


-3

Nhiều truy vấn là con đường để đi. Nếu bạn xử lý các tình huống đơn giản như vậy - chi phí chung của trình tối ưu hóa truy vấn là một yếu tố. Với nhiều dữ liệu hơn, mạng không hiệu quả của phép nối (hàng dự phòng) xuất hiện. Chỉ với nhiều dữ liệu hơn là có hiệu quả.

Cuối cùng, những gì bạn trải nghiệm là thứ mà nhiều nhà phát triển nhìn thấy. Các DBA luôn nói "không, hãy tham gia" nhưng thực tế là: nhanh hơn để thực hiện nhiều lựa chọn đơn giản trong trường hợp này.


5
Không có "mạng không hiệu quả" trong một liên kết - tất cả đều xảy ra trên máy chủ cơ sở dữ liệu, vì vậy không có mạng nào liên quan (trừ khi bạn tham gia qua một liên kết db!)
Chris Saxon

2
Bạn có thể xem xét liệu lớp mạng có nén hay không. SQL * Net của Oracle, trong đó các giá trị lặp lại trong cùng một cột được nén một cách hiệu quả.
David Aldridge

3
@TomTom bạn có thể có một điểm hoặc không (như David Aldridge, vấn đề nén) nhưng cách diễn đạt của bạn khó hiểu. "Mạng không hiệu quả của việc tham gia" ? Thực sự, sửa nó để nó là hiển nhiên những gì bạn có ý nghĩa.
ypercubeᵀᴹ

@ChrisSaxon chắc chắn có, hình ảnh bạn có các bảng cho báo cáo "title-> base-> table-rows" và bạn cần tất cả các hàng để bạn tham gia vào 3 bảng này. Mỗi bảng có các varchars dài, vì vậy những gì xảy ra là cho mỗi hàng bạn đang lặp lại các varchars dài này. Lớp ứng dụng cần phân bổ bộ nhớ cho tất cả các chuỗi này và sau đó nhóm chúng cho mô hình của bạn. Vì vậy, tôi nghĩ rằng đó là những gì anh ấy muốn nói, có nhiều dữ liệu được gửi hơn
MIKE

@MIKE phụ thuộc vào biểu thức bạn chọn, không phải tham gia. Và có thể có nén mạng. Trong cơ sở dữ liệu Oracle SQL * Net loại bỏ các giá trị trùng lặp lặp đi lặp lại nicetheory.io/2018/01/11/ trên
Chris Saxon
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.