Repro
- Mở SSMS
Nhập nội dung sau vào cửa sổ truy vấn mới
use <YourDatabase>;
go
- Chuyển đến Object Explorer (SSMS) và nhấp chuột phải vào
<YourDatabase>
-> Tasks
->Take Offline
Mở một cửa sổ truy vấn mới thứ hai và gõ như sau:
use <YourDatabase>;
go
Bạn sẽ được nhắc với thông báo sau:
Msg 952, Cấp 16, Trạng thái 1,
Cơ sở dữ liệu Dòng 1 'TestDb1' đang trong quá trình chuyển đổi. Hãy thử tuyên bố sau.
Lý do điều này xảy ra có thể được tìm thấy từ một truy vấn chẩn đoán tương tự với truy vấn dưới đây:
select
l.resource_type,
l.request_mode,
l.request_status,
l.request_session_id,
r.command,
r.status,
r.blocking_session_id,
r.wait_type,
r.wait_time,
r.wait_resource,
request_sql_text = st.text,
s.program_name,
most_recent_sql_text = stc.text
from sys.dm_tran_locks l
left join sys.dm_exec_requests r
on l.request_session_id = r.session_id
left join sys.dm_exec_sessions s
on l.request_session_id = s.session_id
left join sys.dm_exec_connections c
on s.session_id = c.session_id
outer apply sys.dm_exec_sql_text(r.sql_handle) st
outer apply sys.dm_exec_sql_text(c.most_recent_sql_handle) stc
where l.resource_database_id = db_id('<YourDatabase>')
order by request_session_id;
Để biết giá trị của nó, bạn không cần Object Explorer để tái tạo lỗi này. Bạn chỉ cần một yêu cầu bị chặn đang cố thực hiện thao tác tương tự (trong trường hợp này, hãy lấy cơ sở dữ liệu ngoại tuyến). Xem ảnh chụp màn hình bên dưới để biết ba bước trong T-SQL:
Những gì bạn rất có thể sẽ thấy là phiên Object Explorer của bạn bị chặn bởi một phiên khác (được hiển thị bởi blocking_session_id
). Phiên Object Explorer đó sẽ cố lấy khóa độc quyền ( X
) trên cơ sở dữ liệu. Trong trường hợp của repro ở trên, phiên Object Explorer đã được cấp khóa cập nhật ( U
) và cố gắng chuyển đổi thành khóa độc quyền ( X
). Nó có một Wait_type của LCK_M_X
, bị chặn bởi phiên của chúng tôi được đại diện bởi cửa sổ truy vấn đầu tiên ( use <YourDatabase>
lấy khóa chia sẻ ( S
) trên cơ sở dữ liệu).
Và sau đó, lỗi này xuất phát từ một phiên khác đang cố khóa và thông báo lỗi này dẫn đến việc từ chối phiên để có quyền truy cập vào cơ sở dữ liệu đang cố chuyển sang trạng thái khác (trong trường hợp này là trạng thái trực tuyến để chuyển đổi ngoại tuyến).
Lần sau bạn nên làm gì?
Trước hết, đừng hoảng sợ và đừng bắt đầu bỏ cơ sở dữ liệu . Bạn cần thực hiện một phương pháp khắc phục sự cố (với một truy vấn chẩn đoán tương tự như ở trên) để tìm hiểu lý do tại sao bạn nhìn thấy những gì bạn đang thấy. Với một thông báo như vậy hoặc khi một cái gì đó xuất hiện "treo", bạn sẽ tự động cho rằng thiếu đồng thời và bắt đầu đào sâu vào việc chặn ( sys.dm_tran_locks
là một khởi đầu tốt).
Là một lưu ý phụ, tôi thực sự tin rằng bạn là tốt nhất để tìm ra gốc rễ của một vấn đề trước khi thực hiện bất kỳ hành động ngẫu nhiên. Không chỉ với thao tác này, mà còn phù hợp với mọi hành vi mà bạn không mong đợi. Biết những gì thực sự gây ra vấn đề của bạn, rõ ràng nó thực sự không phải là vấn đề lớn. Về cơ bản, bạn đã có một chuỗi chặn và trình chặn cha mẹ là thứ mà rất có thể bạn đã đưa ra KILL
hoặc nếu đó là yêu cầu của phiên mà bạn không muốn KILL
thì bạn có thể đợi cho đến khi hoàn thành. Dù bằng cách nào, bạn sẽ có kiến thức để đưa ra quyết định đúng đắn và thận trọng dựa trên kịch bản cụ thể của bạn (khôi phục hoặc chờ cam kết).
Một điều đáng chú ý khác, đây là một trong những lý do tại sao tôi luôn chọn phương án thay thế T-SQL thay vì GUI. Bạn biết chính xác những gì bạn đang thực hiện với T-SQL và SQL Server đang làm gì. Rốt cuộc, bạn đã ban hành lệnh rõ ràng. Khi bạn sử dụng GUI, T-SQL thực tế sẽ là một sự trừu tượng hóa. Trong trường hợp này, tôi đã xem xét nỗ lực của Object Explorer bị chặn để lấy cơ sở dữ liệu ngoại tuyến và nó đã được ALTER DATABASE <YourDatabase> SET OFFLINE
. Không có nỗ lực để quay trở lại, đó là lý do tại sao nó đã chờ đợi vô thời hạn. Trong trường hợp của bạn, nếu bạn muốn quay lại các phiên có khóa trên cơ sở dữ liệu đó, ALTER DATABASE ... SET OFFLINE WITH ROLLBACK IMMEDIATE
thì rất có thể bạn sẽ bị thiếu khả năng nếu bạn đã xác định ban đầu rằng rollback là ổn.