Các câu lệnh SQL có thể thực thi đồng thời trong một phiên duy nhất trong SQL Server không?


16

Tôi đã viết một thủ tục được lưu trữ trong đó sử dụng một bảng tạm thời. Tôi biết rằng trong SQL Server, các bảng tạm thời có phạm vi phiên. Tuy nhiên, tôi không thể tìm thấy thông tin chính xác về chính xác những gì một phiên có khả năng. Đặc biệt, nếu quy trình được lưu trữ này có thể thực hiện hai lần đồng thời trong một phiên duy nhất, thì cần có mức cách ly cao hơn đáng kể cho một giao dịch trong quy trình đó do hai lần thực hiện chia sẻ một bảng tạm thời.

Câu trả lời:


19

Trong khi câu trả lời của dầu Brent là đúng cho cho tất cả các mục đích thực tế, và đây không phải là một cái gì đó mà tôi từng thấy một người nào đó lo lắng về, nó có thể cho nhiều lời gọi của một thủ tục lưu trữ trong một phiên để ảnh hưởng lẫn nhau thông qua một bảng #temp phiên scoped .

Tin tốt là nó cực kỳ khó xảy ra trong tự nhiên bởi vì

1) #Temp bảng được khai báo bên trong một thủ tục được lưu trữ hoặc các lô được lồng không thực sự có khả năng hiển thị phiên (hoặc trọn đời). Và đây là bởi đến nay các trường hợp phổ biến nhất.

2) Nó yêu cầu MultipActiveResultsets và một số chương trình máy khách không đồng bộ rất lạ hoặc để thủ tục được lưu trữ trả về một tập kết quả ở giữa và máy khách gọi một phiên bản khác của thủ tục được lưu trữ trong khi xử lý kết quả từ lần đầu tiên.

Đây là một ví dụ giả định:

using System;
using System.Data.SqlClient;

namespace ado.nettest
{
    class Program
    {
        static void Main(string[] args)
        {
            using (var con = new SqlConnection("Server=localhost;database=tempdb;integrated security=true;MultipleActiveResultSets = True"))
            {
                con.Open();

                var procDdl = @"
create table #t(id int)
exec ('
create procedure #foo
as
begin
  insert into #t(id) values (1);
  select top 10000 * from sys.messages m, sys.messages m2;
  select count(*) rc from #t;
  delete from #t;
end
');
";
                var cmdDDL = con.CreateCommand();
                cmdDDL.CommandText = procDdl;
                cmdDDL.ExecuteNonQuery();

                var cmd = con.CreateCommand();
                cmd.CommandText = "exec #foo";
                using (var rdr = cmd.ExecuteReader())
                {
                    rdr.Read();

                    var cmd2 = con.CreateCommand();
                    cmd2.CommandText = "exec #foo";
                    using (var rdr2 = cmd2.ExecuteReader())
                    {

                    }

                    while (rdr.Read())
                    {

                    }
                    rdr.NextResult();
                    rdr.Read();
                    var rc = rdr.GetInt32(0);
                    Console.WriteLine($"Numer of rows in temp table {rc}");

                }


            }

            Console.WriteLine("Hit any key to exit");
            Console.ReadKey();
        }
    }
}

đầu ra nào

Numer of rows in temp table 0
Hit any key to exit

bởi vì lệnh gọi thứ hai của thủ tục được lưu trữ đã chèn một hàng và sau đó xóa tất cả các hàng khỏi #t trong khi lệnh gọi đầu tiên đang chờ máy khách tìm nạp các hàng từ tập kết quả đầu tiên. Lưu ý rằng nếu tập kết quả đầu tiên nhỏ, các hàng có thể được đệm và thực thi có thể tiếp tục mà không gửi bất cứ thứ gì cho máy khách.

Nếu bạn di chuyển

create table #t(id int)

vào thủ tục lưu trữ, nó xuất ra:

Numer of rows in temp table 1
Hit any key to exit

Và với bảng tạm thời được khai báo bên trong thủ tục, nếu bạn thay đổi truy vấn thứ hai thành

cmd2.CommandText = "select * from #t";

Nó thất bại với:

'Tên đối tượng không hợp lệ' #t '.'

Bởi vì bảng #temp được tạo bên trong một thủ tục được lưu trữ hoặc lô được lồng chỉ có thể nhìn thấy trong quy trình hoặc lô được lưu trữ đó và trong các quy trình và lô được lồng mà nó gọi và bị hủy khi thủ tục hoặc lô kết thúc.


12

Không đồng thời. Các tùy chọn của bạn bao gồm:

  • Chạy các truy vấn lần lượt trong cùng một phiên
  • Chuyển từ bảng tạm thời sang bảng tạm thời toàn cầu (sử dụng ## TableName thay vì #TableName), nhưng lưu ý rằng bảng tạm thời toàn cầu sẽ tự động bị hủy khi phiên tạo bảng tạm thời đóng lại và không có phiên hoạt động nào khác với một tham chiếu đến nó
  • Chuyển sang bảng người dùng thực trong TempDB - bạn có thể tạo các bảng ở đó, nhưng lưu ý rằng chúng sẽ biến mất khi khởi động lại máy chủ
  • Chuyển sang bảng người dùng thực trong cơ sở dữ liệu người dùng
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.