Tạo kết nối cơ sở dữ liệu - Thực hiện một lần hoặc cho mỗi truy vấn?


101

Hiện tại tôi tạo kết nối cơ sở dữ liệu khi trang web của tôi được tải lần đầu tiên. Sau đó tôi xử lý trang và chạy bất kỳ truy vấn nào đối với kết nối đó. Đây có phải là cách tốt nhất để làm điều đó hay tôi nên tạo kết nối cơ sở dữ liệu mỗi khi tôi chạy truy vấn?

ps Có ý nghĩa hơn với tôi khi tạo 1 kết nối và sử dụng nó nhưng tôi không biết liệu điều này có thể gây ra bất kỳ vấn đề nào khác không.

Tôi đang sử dụng C # (ASP.NET) với MSSQL.

Câu trả lời:


124

Nếu bạn tạo một truy vấn / giao dịch, việc quản lý "đóng" các kết nối sẽ dễ dàng hơn nhiều.

Tôi có thể thấy lý do tại sao ý thức thông thường ra lệnh rằng bạn nên mở một cái và sử dụng nó xuyên suốt, nhưng bạn sẽ gặp vấn đề với các kết nối bị rớt và đa luồng. Vì vậy, bước tiếp theo của bạn sẽ là mở một nhóm, nói về 50, kết nối và giữ cho tất cả chúng mở, chuyển chúng ra các quy trình khác nhau. Và sau đó bạn sẽ phát hiện ra rằng đây chính xác là những gì .NET framework làm cho bạn .

Nếu bạn mở một kết nối khi bạn cần và loại bỏ nó khi bạn kết thúc, điều đó sẽ không thực sự đóng kết nối, nó sẽ chỉ đưa nó trở lại nhóm kết nối để sử dụng lại.


Chỉ đọc bài viết đó khi bạn đăng nó :) Cảm ơn.
webnoob

2
Trang web bạn liên kết đến dành riêng cho SQL Server. .NET cũng cung cấp tự động tổng hợp khi kết nối với các cơ sở dữ liệu khác, ví dụ: Oracle, Sqlite, MySql?
briddums

@briddums - Tôi nghĩ rằng phụ thuộc vào kết nối. .Net, ví dụ, không cung cấp trình kết nối MySql. Nó được viết và duy trì bởi MySql. Và trong khi nó hoạt động, theo kinh nghiệm của tôi, việc thực hiện trước đó không phải là lỗi.
ZweiBlumen

1
@briddums: Phụ thuộc vào lắp ráp nhà cung cấp. Tôi chắc chắn rằng cả triển khai Oracle của Microsoft và của riêng Oracle đều hỗ trợ tổng hợp kết nối, bởi vì tôi đã sử dụng chúng. Tôi đã nghe nói rằng có một MySql hoạt động và tôi mong các nhà cung cấp trong Spring.NET hỗ trợ nhóm, nhưng tốt hơn hết là bạn nên tìm kiếm hoặc hỏi trực tiếp nhà cung cấp hơn là hỏi tôi.
pdr

1
Cần biết rằng việc mở, chạy truy vấn và xử lý một kết nối, ngay cả trong một vòng lặp, cũng nhanh như nhau, và đôi khi NHANH CHÓNG hơn là mở nó một lần và lặp lại truy vấn. Luôn luôn xử lý. Nó an toàn hơn và NHANH CHÓNG. Đừng lo lắng về chi phí kết nối từ hồ bơi - điều đó thật tầm thường.
smdrager

38

Thực hành tốt nhất để tạo một kết nối cho mỗi truy vấn - và trong trường hợp hiển thị dữ liệu, thực tiễn tốt nhất là truy vấn mang lại tất cả dữ liệu cần thiết trong một lần.

Thông tin lai lịch:

Trong .NET, gọi SqlConnection.Open()theo mặc định sẽ luôn sử dụng kết nối trong suốt kết nối (xem "Sử dụng kết nối nhóm với SQL Server" trên MSDN). Vì vậy, bạn có thể lấy một kết nối mới bằng cách sử dụng Open()và gọi Close()khi bạn hoàn thành và .NET sẽ thực hiện đúng.

Lưu ý rằng không có nhóm kết nối, một kết nối cho mỗi truy vấn sẽ là một ý tưởng rất tệ bởi vì việc tạo kết nối cơ sở dữ liệu thực sự có thể rất tốn kém (xác thực, phí mạng, v.v.) và số lượng kết nối mở đồng thời thường rất hạn chế.


7
@webnoob - Vì .NET sử dụng kết nối tổng hợp, không, không. Lý do là các kết nối có thể bị đóng, phân bổ lại, v.v. - vì vậy việc sử dụng lại kết nối không phải là cách làm tốt.
Oded

11
-1 Câu trả lời khá sai lệch. Tạo một kết nối cho mỗi truy vấn là một ý tưởng rất xấu. Điều bạn có thể muốn nói là "truy xuất một kết nối mới cho mỗi truy vấn từ nhóm kết nối" - nhưng điều đó không giống với việc tạo kết nối.
sleske

1
@sleske - Làm thế nào khác với câu trả lời của pdr?
Oded

3
@Oded: À, tôi hiểu rồi. Trong .NET, gọi SqlConnection.Open()sẽ luôn luôn sử dụng kết nối tổng hợp. Vì vậy, sự khác biệt giữa "mở một kết nối" và "truy xuất một kết nối từ một nhóm" không tồn tại. Sự hiểu lầm của tôi. Tôi đã tự do chỉnh sửa một chút giải thích cho câu hỏi, và lấy lại phiếu bầu.
sleske

2
@ Eaglei22 - chắc chắn nên làm như vậy (xem docs.microsoft.com/en-us/dotnet/framework/data/adonet/ Lỗi ). Nói chung, bạn sẽ muốn trả lại kết nối cho nhóm càng sớm càng tốt, tuy nhiên, nếu bạn đang đưa ra một số truy vấn theo trình tự, thể tốt hơn là sử dụng lại kết nối như bạn đề xuất. Bạn sẽ cần kiểm tra và xem phương pháp nào tốt hơn cho mình (Tôi không biết bạn sử dụng tiêu chí nào - kiểm tra cả hai cách và xem hiệu quả trên các số liệu bạn đã chọn).
Oded

0

Hãy nhớ tất cả điều này là trong bối cảnh của hệ sinh thái .Net.

Các nhà phát triển đôi khi muốn "tối ưu hóa" mã của họ để sử dụng lại các đối tượng kết nối của họ. Với bối cảnh của câu hỏi này, điều này gần như luôn luôn là một sai lầm.

ADO.Net có một tính năng gọi là Kết nối tổng hợp . Khi bạn tạo và mở một đối tượng kết nối mới, những gì bạn thực sự đang làm là yêu cầu kết nối từ một nhóm. Khi bạn đóng một kết nối, bạn trả nó về hồ bơi.

Điều quan trọng là phải hiểu các đối tượng chúng ta sử dụng trực tiếp trong mã: SqlConnection, MySqlConnection, OleDbConnectio, v.v., tất cả chỉ là các trình bao bọc xung quanh một kết nối cơ bản thực sự được quản lý bởi ADO.Net và các kết nối thực của ADO.Net "nặng" hơn và đắt hơn từ quan điểm hiệu suất. Đó là những đối tượng cơ bản có các mối lo ngại như xác thực, truyền mạng, mã hóa và những thứ đó vượt xa số lượng bộ nhớ nhỏ trong đối tượng bạn thực sự nhìn thấy trong mã của riêng bạn.

Khi bạn cố gắng sử dụng lại đối tượng kết nối của mình, bạn sẽ phá vỡ khả năng ADO.Net để quản lý hiệu quả các kết nối cơ bản quan trọng. Bạn đạt được hiệu quả trong việc nhỏ với chi phí của điều lớn hơn nhiều.

Việc sử dụng lại kết nối qua một ứng dụng hoặc yêu cầu http cũng có thể buộc bạn vô tình nối tiếp thứ gì đó có thể chạy song song và trở thành nút cổ chai hiệu năng. Tôi đã thấy điều này xảy ra trong các ứng dụng thực tế.

Trong trường hợp ví dụ về trang web ở đây, nơi bạn ít nhất chỉ giữ kết nối nhỏ trong suốt thời gian của một yêu cầu / phản hồi http, bạn có thể đạt được hiệu quả cao hơn bằng cách đánh giá những truy vấn nào bạn chạy trong đường dẫn yêu cầu của mình và thử nhận chúng xuống càng ít yêu cầu riêng biệt đến cơ sở dữ liệu càng tốt (gợi ý: bạn có thể gửi nhiều truy vấn trong một chuỗi SQL và sử dụng DataReader.NextResult()hoặc kiểm tra các bảng khác nhau DataSetđể di chuyển giữa chúng).

Nói cách khác, thay vì suy nghĩ về việc sử dụng lại một kết nối cho một ứng dụng hoặc yêu cầu http so với một kết nối cho mỗi truy vấn, hãy nghĩ về một kết nối cho mỗi lần bạn gọi ra cơ sở dữ liệu ... mỗi chuyến đi khứ hồi. Sau đó cố gắng giảm thiểu số lượng kết nối bằng cách giảm thiểu số lượng các chuyến đi đó. Bằng cách này, bạn có thể đáp ứng cả hai mục tiêu.


Nhưng đó chỉ là một loại tối ưu hóa. Ngoài ra còn tối ưu hóa thời gian lập trình viên và đạt được việc sử dụng lại mã hiệu quả. Các nhà phát triển không muốn viết đi viết lại cùng một mã nồi hơi để có được một đối tượng kết nối mở và sẵn sàng sử dụng. Nó không chỉ tẻ nhạt, đó là một cách để giới thiệu các lỗi vào một chương trình.

Mặc dù ở đây, nói chung, tốt hơn là có một kết nối cho mỗi truy vấn (hoặc chuyến đi khứ hồi). Có những mẫu khác mà bạn có thể sử dụng để giúp tránh viết lại mã soạn sẵn. Đây là một ví dụ tôi thích, nhưng có nhiều ví dụ khác.


Tôi đến bữa tiệc muộn, nhưng tôi nghĩ câu trả lời này bao gồm một số điểm quan trọng :)
Joel Coehoorn
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.