Những gì đủ điều kiện mà quá nhiều cơ sở dữ liệu yêu cầu mã trong mã?


17

Đây là một cuộc thảo luận bản thân tôi và một số đồng nghiệp của tôi đang có và nghĩ rằng tôi sẽ ra đây và xem nếu có sự đồng thuận chung về nó.

Về cơ bản, nó đưa ra 2 ý kiến ​​sau đây về các cuộc gọi cơ sở dữ liệu: 1. Thực hiện một cuộc gọi lớn để nhận mọi thứ cần thiết để giảm cơ sở dữ liệu số lượng cuộc gọi DB 2. Thực hiện các cuộc gọi riêng nhỏ hơn dựa trên những gì được yêu cầu để giảm kích thước Cuộc gọi DB

Trường hợp này đặc biệt đi vào chơi là trong mã phổ biến. Chúng ta sẽ sử dụng ví dụ về một lớp Nhân viên vì điều đó khá đơn giản.

Giả sử rằng lớp Nhân viên của bạn có 10 thuộc tính giá trị (tên, họ, thuê, v.v.) và sau đó 2 thuộc tính lớp ... 1 chỉ vào một lớp Bộ và sau đó 1 giám sát viên trỏ lại một đối tượng Nhân viên khác.

Trong suy nghĩ số 1, bạn sẽ thực hiện một cuộc gọi trả về dữ liệu Nhân viên cũng như các trường cần thiết để điền các thuộc tính của Bộ và Giám sát viên ... hoặc ít nhất là các trường thường được sử dụng từ các đối tượng phụ đó.

Trong suy nghĩ số 2, ban đầu, bạn chỉ cư trú đối tượng Nhân viên và sau đó chỉ điền vào các đối tượng Bộ và Giám sát nếu và khi chúng thực sự được yêu cầu.

Lập trường của 2 khá đơn giản ... giảm thiểu kích thước của các yêu cầu và số lượng đối tượng cơ sở dữ liệu cần phải được thực hiện mỗi khi một trong những yêu cầu đó được thực hiện. Quan điểm của # 1 là ngay cả khi nó có thể được triển khai đúng cách, thì thực tế là mã sẽ phải tạo nhiều kết nối sẽ gây ra nhiều căng thẳng hơn cho kết nối giữa máy chủ web và cơ sở dữ liệu thay vì giảm nó.

Động lực thúc đẩy nghiên cứu này là lượng lưu lượng giữa máy chủ web và máy chủ cơ sở dữ liệu của chúng tôi vượt khỏi tầm kiểm soát.


7
Theo kinh nghiệm của tôi, không có "câu trả lời đúng" cho vấn đề này. Có sự cân bằng giữa độ trễ và thông lượng. Độ trễ thấp có thể chấp nhận rất nhiều yêu cầu nhỏ hoặc thậm chí một yêu cầu lớn; tuy nhiên, các liên kết có độ trễ cao có xu hướng tốt hơn khi di chuyển nhiều dữ liệu cùng một lúc. Tuy nhiên, nếu thông lượng thấp trong cấu hình độ trễ cao, tốt hơn hết bạn nên tìm nạp các phần nhỏ hơn để phản ứng nhanh hơn.

3
Có lẽ liên quan đến n + 1 vấn đề stackoverflow.com/questions/97197/ từ
Valera Kolupaev

@Valera: để thuận tiện ở đây là liên kết được đăng trên câu hỏi đó: realsolve.co.uk/site/tech/hib-tip-pitfall.php?name=n1selects
rwong

4
"lượng lưu lượng giữa máy chủ web và máy chủ cơ sở dữ liệu của chúng tôi vượt khỏi tầm kiểm soát." Điều đó nghĩa là gì? Bạn có thể cụ thể về vấn đề thực sự là gì? Bạn có vấn đề về hiệu suất? Bạn đã thực hiện hồ sơ và đo lường? Vui lòng cung cấp kết quả thực tế từ các phép đo thực tế như là một phần của câu hỏi. Mặt khác, chúng tôi chỉ đoán.
S.Lott

Câu trả lời:


8

Nếu động lực đằng sau câu hỏi này là quá nhiều lưu lượng truy cập, bạn đã xem xét bộ nhớ đệm đối tượng thường xuyên sử dụng chưa? Ví dụ: Sau khi bạn nhận được các đối tượng Nhân viên và Bộ phận và Giám sát viên, có thể nên thêm chúng vào bộ đệm để nếu chúng được yêu cầu lại trong tương lai gần, chúng đã được lưu vào bộ đệm và không cần phải truy xuất lần nữa. Tất nhiên, bộ đệm sẽ cần phải để các đối tượng hiếm khi sử dụng hết hạn và cũng cần có thể xóa các đối tượng đã được ứng dụng sửa đổi và lưu lại vào cơ sở dữ liệu.

Tùy thuộc vào ngôn ngữ và khung công tác nào bạn đang sử dụng, có thể đã có một khung bộ đệm có thể thực hiện một số (hoặc hầu hết) những gì bạn cần. Nếu bạn sử dụng Java, bạn có thể xem xét Apache Commons-Cache (Tôi đã không sử dụng nó trong một thời gian và trong khi nó trông không hoạt động, nó vẫn có sẵn để sử dụng và lần đầu tiên tôi sử dụng nó khá tốt).


3

Luôn luôn dễ đọc và rõ ràng trong lần đầu tiên bạn viết một cái gì đó. Sau đó, bạn có thể tái cấu trúc nếu và khi bạn cần. Thực hiện kiểm tra tải để tìm ra các nút cổ chai, trong nhiều trường hợp, đây không phải là số lượng cuộc gọi gây ra sự cố mà là các cuộc gọi được viết xấu.

Đối với những gì phân loại quá nhiều, điều đó phụ thuộc vào ứng dụng. Đối với hầu hết các ứng dụng web, mọi thứ dưới 30 giây chỉ ở mức chấp nhận được. Tôi sẽ nói với người dùng của bạn như mong đợi của họ.


Điều gì tạo nên một cuộc gọi db được viết xấu?
nu everest

3

Câu hỏi của bạn dường như dựa trên giả định rằng bạn phải đoán dữ liệu nào sẽ cần cho bất kỳ trang nào. Đó không phải là trường hợp. Cách này không dễ như cách tiếp cận ngây thơ, nhưng bạn có thể kiến ​​trúc mã của mình để bạn biết liệu bạn sẽ cần các thuộc tính của bộ phận hoặc người giám sát trước khi thực hiện bất kỳ cuộc gọi cơ sở dữ liệu nào.


3

Đây là những quy tắc tôi sử dụng, có thể chúng sẽ được sử dụng cho bạn.

  1. Đo lường trước! Tôi thậm chí sẽ không nhìn vào mã "có thể chậm" trừ khi tôi thực sự có thể thấy lưu lượng truy cập chảy vào tài nguyên đó và tài nguyên đó đang phản hồi chậm.
  2. 1 Yêu cầu = K truy vấn. Số lần tôi nói chuyện với cơ sở dữ liệu được xác định đầy đủ bởi loại tài nguyên được yêu cầu; và không bao giờ theo bản chất của yêu cầu hoặc trạng thái của tài nguyên đó; Trong ví dụ của bạn, đó có thể là tối đa 3 truy vấn: 1 cho nhân viên, 1 cho các phòng ban và 1 cho giám sát viên; Không quan trọng có bao nhiêu trong số đó xảy ra.
  3. Đừng truy vấn những gì bạn sẽ không sử dụng . Nếu đây là HTTP mà chúng ta đang nói đến, thì không có ý nghĩa gì trong việc truy vấn dữ liệu cho lần sau; không có sau này; mỗi yêu cầu bắt đầu từ một bảng đá sạch. Đôi khi tôi cần hầu hết các cột từ một bảng, nhưng đôi khi tôi chỉ cần một hoặc hai; khi tôi biết chính xác các lĩnh vực tôi cần, tôi sẽ yêu cầu điều đó.
  4. Ném phần cứng vào vấn đề. Máy chủ có giá rẻ; Đôi khi bạn có thể có đủ hiệu suất chỉ bằng cách di chuyển cơ sở dữ liệu vào hộp mạnh hơn; hoặc gửi một số truy vấn đến một bản sao chỉ đọc.
  5. Đầu tiên làm mất hiệu lực bộ đệm, sau đó thực hiện bộ đệm. Sự thôi thúc thường xuyên sử dụng hoặc khó truy vấn dữ liệu trong bộ đệm là mạnh; nhưng tất cả quá thường xuyên, việc đuổi dữ liệu không sử dụng hoặc dữ liệu thay thế hết hạn bị bỏ qua. Nếu bạn biết cách lấy dữ liệu ra khỏi bộ đệm; sau đó bạn an toàn đặt nó vào bộ đệm; Nếu nó trở nên đắt hơn để làm mất hiệu lực bộ đệm hơn là chỉ thực hiện truy vấn; sau đó bạn không cần một bộ đệm.

2

Cả hai chiến lược ở đây là hoàn toàn hợp lệ. Có những ưu điểm và nhược điểm đối với mỗi:

Một cuộc gọi cho cả 3 đối tượng:

  • sẽ thực hiện nhanh hơn
  • sẽ giúp bạn có được chính xác những gì bạn cần trong trường hợp bạn cần nó
  • có lẽ sẽ chỉ được sử dụng trong một trường hợp (mặc dù đây có thể là trường hợp rất phổ biến)
  • sẽ khó khăn hơn để duy trì
  • sẽ phải được duy trì thường xuyên hơn (vì nó sẽ thay đổi nếu có bất kỳ lược đồ nào trong 3 đối tượng hoặc thay đổi dữ liệu cần thiết)

Một cuộc gọi cho mỗi đối tượng (tổng cộng 3 cuộc gọi)

  • Cung cấp cho bạn một cuộc gọi có mục đích chung để đưa vào một thể hiện duy nhất của từng loại đối tượng; sau đó chúng có thể được sử dụng độc lập
  • Sẽ dễ bảo trì hơn vì cấu trúc truy vấn sẽ đơn giản hơn.
  • Sẽ chậm hơn (không nhất thiết phải chậm gấp 3 lần, nhưng chi phí tăng cho cùng một dữ liệu)
  • Có thể gây ra sự cố với việc truy xuất dữ liệu không cần thiết (kéo toàn bộ hồ sơ khi bạn cần một trường là lãng phí)
  • Có thể gây ra sự cố N + 1 khi tồn tại mối quan hệ nhiều-một, nếu truy vấn một bản ghi được gửi N lần, mỗi lần một bản ghi trong bộ sưu tập.

Đáp lại một vài mối quan tâm của bạn (số 3 và 5 trong danh sách thứ hai) ... Điều gì xảy ra nếu Giám sát viên và Bộ phận chỉ được sử dụng 1/3 (hoặc ít hơn) thời gian? Điều gì xảy ra nếu mã được thiết kế để có được tất cả trẻ em ngay khi đối tượng Danh sách <> được mã hóa để chứa chúng lần đầu tiên được tham chiếu? ... điều đó sẽ giảm bớt sự cảnh giác?
dùng107775

Nếu các đối tượng phụ trợ chỉ hiếm khi cần thiết, thì trong trường hợp chung, việc này sẽ thực hiện nhanh hơn (ít dữ liệu để truy xuất hơn) nhưng trường hợp xấu nhất sẽ chậm hơn (cùng dữ liệu hoặc được truy xuất nhiều hơn, sử dụng ba lần tổng phí truyền thông từ máy tính của bạn). Đối với vấn đề N + 1, bạn chỉ cần có khả năng kiến ​​trúc truy vấn truy xuất danh sách các đối tượng để có thể thực hiện dựa trên khóa ngoài vào phía "một" của mối quan hệ, sau đó kéo nhiều hàng ra khỏi kết quả truy vấn. Bạn không thể sử dụng một phiên bản của truy vấn phải có khóa chính của bản ghi.
KeithS

1

Đối với tôi, Quá nhiều yêu cầu DB đang thực hiện nhiều yêu cầu hơn bạn cần tải dữ liệu bạn yêu cầu tại bất kỳ thời điểm nào.

Vì vậy, tôi không cần dữ liệu, đừng lãng phí bộ nhớ để tránh chuyến đi thứ hai sau đó. Nhưng nếu bạn cần lượng dữ liệu, bạn nên giảm thiểu các cuộc gọi đến db.

Vì vậy, có cả hai tùy chọn, và sử dụng từng tùy chọn trong trường hợp tình huống yêu cầu.

EDIT: Hãy nhớ rằng khóa học này cũng phụ thuộc vào tình huống của bạn. Ví dụ, nếu là ứng dụng WebApp, bạn nên có những cân nhắc khác với ứng dụng máy tính để bàn truy cập DB trong mạng của bạn, trái ngược với trên web cho WepApp.


Điều gì xảy ra trong trường hợp bạn đang viết mã chung và bạn không chắc chắn về cách sử dụng mã của mình. Có thể bạn sẽ không bao giờ hình dung ai đó không cần Người giám sát nhưng hóa ra ứng dụng bạn làm việc là ứng dụng duy nhất cần. Chắc chắn, bạn có thể viết các hàm riêng biệt ... một để không bao gồm nó và một chức năng khác để bao gồm nó nhưng tại thời điểm nào thì mã chung của bạn bắt đầu yêu cầu quá nhiều kiến ​​thức chi tiết để sử dụng?
user107775

@ user107775 Tôi thường chỉ viết hai hàm cho mỗi trường hợp; một chỉ trả về các giá trị thuộc tính và một trả về lớp với tất cả các lớp liên quan. Điều này là do lần MOST, bạn chỉ cần các thuộc tính. Bằng cách này, bạn không cần kiến ​​thức chi tiết, chỉ cần một người có được những điều cơ bản và mọi thứ khác. Tôi thấy đó là một sự cân bằng hợp lý. (Tuy nhiên, một số trường hợp đặc biệt yêu cầu tối ưu hóa nhiều hơn, nhưng đó là trên cơ sở từng trường hợp).
AJC

1

Kết nối với DB, gửi yêu cầu và phân tích cú pháp thường mất thời gian đáng kể so với truy xuất kết quả, vì vậy xu hướng chung là ghép càng nhiều truy vấn càng tốt trong một yêu cầu.

Tuy nhiên, làm tất cả trong một lần bắn sẽ khiến mã không thể nhầm lẫn. Thay vào đó, nó thường đạt được bởi một lớp trừu tượng bổ sung: mã lập lịch một số yêu cầu khi cần, sau đó công cụ phân tích cú pháp này thành một yêu cầu lớn (có thể sử dụng bộ đệm trên đường) và sau đó trả lời được gửi đi khi cần.

Tất nhiên không phải lúc nào tất cả đều có thể được truy xuất trong một truy vấn - bạn sẽ thường có một truy vấn cung cấp dữ liệu cần thiết để xây dựng truy vấn tiếp theo, vì vậy bạn sẽ phải lặp lại nó. Vẫn còn các gói truy vấn đáng kinh ngạc và thực hiện càng nhiều càng tốt cùng một lúc tốt hơn hàng trăm bức ảnh nhỏ vào cơ sở dữ liệu.

Vì vậy, hãy lập kế hoạch những gì bạn cần, yêu cầu và truy xuất nó, nếu cần nhiều hơn, yêu cầu và lấy lại nó, sau đó sử dụng dữ liệu trong việc tạo nội dung. Chắc chắn tránh sử dụng các yêu cầu cơ sở dữ liệu như khởi tạo biến cục bộ nằm rải rác trên toàn bộ mã.


1

Chúng tôi không biết đủ về ứng dụng của bạn để biết lựa chọn nào bạn có lỗi khi tối ưu hóa quá sớm. Dữ liệu Giám sát được sử dụng thường xuyên như thế nào? Có vẻ như nó có thể là một sự lãng phí, nhưng chúng ta không biết. Nếu bạn tách chúng ra, bạn có thể theo dõi hệ thống của mình để xem tần suất chúng được sử dụng cùng nhau. Hơn bạn có thể đưa ra quyết định chỉ kết hợp chúng trong một cuộc gọi. Mặt khác, nếu bạn bắt đầu tạo ra một cổ chai với một cuộc gọi lớn này, bạn bắt đầu gặp rắc rối ở đâu? Khó xác định những gì có ý nghĩa để bỏ qua. Nhiều trường dữ liệu có thể được thêm vào quá trình này.

Sẽ rất thú vị khi biết bao nhiêu thứ này đến từ bộ nhớ db so với đĩa. Không có gì khiến tôi cảm thấy bộ phận đó ít nhiều có khả năng thay đổi so với địa chỉ.

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.