Sqlserver
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Sqlserver

Phương pháp nhanh nhất để chèn, cập nhật, lựa chọn SQL Server

Câu trả lời này chủ yếu tập trung vào các thao tác 'chọn' so với cập nhật / tạo / xóa. Tôi nghĩ rằng hiếm khi cập nhật nhiều hơn một hoặc một vài bản ghi cùng một lúc, và vì vậy tôi cũng nghĩ 'select' là nơi có xu hướng xảy ra tắc nghẽn. Điều đó nói lên rằng, bạn cần biết đơn xin việc (hồ sơ) của mình. Nơi tốt nhất để tập trung thời gian tối ưu hóa của bạn hầu như luôn ở cấp cơ sở dữ liệu trong chính các truy vấn, chứ không phải là mã máy khách. Tất cả mã khách hàng chỉ là hệ thống ống nước:nó không phải là lực lượng chính của ứng dụng của bạn. Tuy nhiên, vì hệ thống ống nước có xu hướng được sử dụng lại trong nhiều ứng dụng khác nhau, tôi đồng cảm với mong muốn làm cho nó gần với mức tối ưu nhất có thể và do đó tôi có nhiều điều để nói về cách xây dựng mã đó.

Tôi có một phương pháp chung cho các truy vấn / thủ tục được chọn trong lớp dữ liệu của tôi trông giống như sau:

private static IEnumerable<IDataRecord> Retrieve(string sql, Action<SqlParameterCollection> addParameters)
{
    //ConnectionString is a private static property in the data layer
    // You can implement it to read from a config file or elsewhere
    using (var cn = new SqlConnection(ConnectionString))
    using (var cmd = new SqlCommand(sql, cn))
    {
        addParameters(cmd.Parameters);

        cn.Open();
        using (var rdr = cmd.ExecuteReader())
        {
            while (rdr.Read())
                yield return rdr;
            rdr.Close();
        }
    }
}

Và điều đó cho phép tôi viết các phương thức lớp dữ liệu công khai sử dụng các phương thức ẩn danh để thêm các tham số. Mã được hiển thị hoạt động với .Net 2.0+, nhưng có thể được viết ngắn hơn bằng cách sử dụng .Net 3.5:

public IEnumerable<IDataRecord> GetFooChildrenByParentID(int ParentID)
{
    //I could easily use a stored procedure name instead of a full sql query
    return Retrieve(
        @"SELECT c.* 
         FROM [ParentTable] p 
         INNER JOIN [ChildTable] c ON c.ParentID = f.ID 
         WHERE f.ID= @ParentID", delegate(SqlParameterCollection p)
       {
          p.Add("@ParentID", SqlDbType.Int).Value = ParentID;
       }
     );
}

Tôi sẽ dừng ngay tại đây để tôi có thể trỏ lại cho bạn đoạn mã ở trên sử dụng phương thức ẩn danh để tạo tham số.

Đây là mã rất rõ ràng, ở chỗ nó đặt định nghĩa truy vấn và tạo tham số ở cùng một vị trí trong khi vẫn cho phép bạn trừu tượng hóa mã gọi / kết nối cơ sở dữ liệu soạn sẵn sang một nơi nào đó dễ sử dụng hơn. Tôi không nghĩ rằng kỹ thuật này bị che lấp bởi bất kỳ gạch đầu dòng nào trong câu hỏi của bạn và nó cũng diễn ra khá nhanh. Tôi nghĩ rằng điều này bao hàm lực đẩy câu hỏi của bạn.

Tuy nhiên, tôi muốn tiếp tục giải thích tất cả những điều này khớp với nhau như thế nào. Phần còn lại khá đơn giản, nhưng bạn cũng dễ dàng ném điều này vào danh sách hoặc tương tự và làm sai mọi thứ, cuối cùng làm ảnh hưởng đến hiệu suất. Vì vậy, tiếp tục, lớp nghiệp vụ sau đó sử dụng một nhà máy để dịch kết quả truy vấn sang các đối tượng (c # 3.0 trở lên):

public class Foo
{
    //various normal properties and methods go here

    public static Foo FooFactory(IDataRecord record)
    {
        return new Foo
        {
            Property1 = record[0],
            Property2 = record[1]
            //...
        };
    }
}

Thay vì để chúng tồn tại trong lớp của chúng, bạn cũng có thể nhóm tất cả chúng lại với nhau thành một lớp tĩnh nhằm mục đích cụ thể là lưu giữ các phương thức gốc.

Tôi cần thực hiện một thay đổi đối với phương pháp truy xuất ban đầu. Phương thức đó "tạo ra" cùng một đối tượng và điều này không phải lúc nào cũng hoạt động tốt. Những gì chúng tôi muốn làm khác để làm cho nó hoạt động là buộc một bản sao của đối tượng được đại diện bởi bản ghi hiện tại, để khi trình đọc thay đổi cho bản ghi tiếp theo, chúng tôi đang làm việc với dữ liệu sạch. Tôi đã đợi cho đến khi hiển thị phương thức gốc để chúng ta có thể sử dụng phương thức đó trong mã cuối cùng. Phương thức Truy xuất mới trông giống như sau:

private static IEnumerable<T> Retrieve(Func<IDataRecord, T> factory,
                  string sql, Action<SqlParameterCollection> addParameters)
{
    //ConnectionString is a private static property in the data layer
    // You can implement it to read from a config file or elsewhere
    using (var cn = new SqlConnection(ConnectionString))
    using (var cmd = new SqlCommand(sql, cn))
    {
        addParameters(cmd.Parameters);

        cn.Open();
        using (var rdr = cmd.ExecuteReader())
        {
            while (rdr.Read())
                yield return factory(rdr);
            rdr.Close();
        }
    }
}

Và bây giờ chúng ta sẽ gọi phương thức Retrieve () mới như thế này:

public IEnumerable<Foo> GetFooChildrenByParentID(int ParentID)
{
    //I could easily use a stored procedure name instead of a full sql query
    return Retrieve(Foo.FooFactory,
        @"SELECT c.* 
         FROM [ParentTable] p 
         INNER JOIN [ChildTable] c ON c.ParentID = f.ID 
         WHERE f.ID= @ParentID", delegate(SqlParameterCollection p)
       {
          p.Add("@ParentID", SqlDbType.Int).Value = ParentID;
       }
     );
}

Rõ ràng là phương pháp cuối cùng này có thể được mở rộng để bao gồm bất kỳ logic nghiệp vụ bổ sung nào cần thiết. Nó cũng hóa ra mã này đặc biệt nhanh, bởi vì nó tận dụng các tính năng đánh giá lười biếng của IEnumerable. Nhược điểm là nó có xu hướng tạo ra nhiều đối tượng tồn tại trong thời gian ngắn và điều đó có thể ảnh hưởng đến hiệu suất giao dịch mà bạn đã hỏi. Để giải quyết vấn đề này, đôi khi tôi phá vỡ n-tier tốt và chuyển các đối tượng IDataRecord trực tiếp vào tầng trình bày và tránh tạo đối tượng không cần thiết cho các bản ghi chỉ đơn giản là liên kết với điều khiển lưới ngay lập tức.

Cập nhật / Tạo mã cũng tương tự, với sự khác biệt là bạn thường chỉ thay đổi một bản ghi cùng một lúc thay vì nhiều bản ghi.

Hoặc, tôi có thể giúp bạn đọc bài đăng dài này và chỉ bảo bạn sử dụng Entity Framework;)



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. IO STATISTICS trong SQL Server là gì?

  2. Giới hạn đối với điều kiện WHERE col IN (...)

  3. Đã xảy ra lỗi liên quan đến mạng hoặc lỗi cụ thể đối với trường hợp cụ thể khi thiết lập kết nối với SQL Server

  4. Nhận danh sách các múi giờ được hỗ trợ trong SQL Server (T-SQL)

  5. Có thể đặt lược đồ mặc định từ chuỗi kết nối không?