Tham chiếu cơ sở dữ liệu theo chương trình thông qua T-SQL


11

Tôi đang viết một thủ tục được lưu trữ lấy tên cơ sở dữ liệu làm đối số và trả về một bảng các chỉ mục của cơ sở dữ liệu đó và mức độ phân mảnh của chúng. Quy trình được lưu trữ này sẽ sống trong cơ sở dữ liệu DBA của chúng tôi (DB chứa các bảng mà các DBA sử dụng để theo dõi và tối ưu hóa mọi thứ). Các hệ thống được đề cập là tất cả SQL Server 2008 R2 nếu điều đó tạo ra sự khác biệt.

Tôi có một truy vấn cơ bản được thực hiện, nhưng bị mắc kẹt khi cố gắng cung cấp tên thật của các chỉ mục. Theo hiểu biết tốt nhất của tôi, thông tin đó được chứa trong chế độ xem sys.indexes của mỗi cá nhân. Vấn đề cụ thể của tôi là cố gắng tham chiếu chế độ xem đó theo chương trình từ thủ tục lưu trữ của cơ sở dữ liệu khác.

Để minh họa, đây là một phần của truy vấn có vấn đề:

FROM sys.dm_db_index_physical_stats(@db_id,NULL,NULL,NULL,NULL) p
INNER JOIN sys.indexes b ON p.[object_id] = b.[object_id] 
    AND p.index_id = b.index_id 
    AND b.index_id != 0

Truy vấn hoạt động tốt khi được thực thi từ cơ sở dữ liệu được xác định bởi @db_id, bởi vì nó đang sử dụng chế độ xem sys.indexes thích hợp. Tuy nhiên, nếu tôi cố gắng gọi điều này từ cơ sở dữ liệu DBA, tất cả sẽ xuất hiện không, vì chế độ xem sys.indexes dành cho cơ sở dữ liệu sai.

Nói một cách tổng quát hơn, tôi cần có khả năng làm một việc như thế này:

DECLARE @db_name NVARCHAR(255) = 'my_database';
SELECT * FROM @db_name + '.sys.indexes';

hoặc là

USE @db_name;

Tôi đã thử chuyển đổi cơ sở dữ liệu hoặc tham chiếu các cơ sở dữ liệu khác bằng cách sử dụng kết hợp các hàm nối chuỗi và các hàm OBJECT_NAME / OBJECT_ID / DB_ID và dường như không có gì hoạt động. Tôi đánh giá cao bất kỳ ý tưởng nào mà cộng đồng có thể có, nhưng nghi ngờ tôi sẽ phải kiểm tra lại quy trình được lưu trữ này để cư trú trong mỗi cơ sở dữ liệu riêng lẻ.

Cảm ơn trước cho các đề nghị.


1
Tôi nghi ngờ bạn sẽ cần sử dụng SQL động cho điều này ...
JNK

Câu trả lời:


10

SQL động có ích cho các loại nhiệm vụ quản trị này. Đây là một đoạn trích từ một thủ tục được lưu trữ mà tôi đã viết rằng không chỉ có các mức độ phân mảnh, mà còn tạo ra mã để thực hiện phân mảnh:

select @SQL = 
'
select getdate(),
       ''' + @@ServerName + ''',
       ''' + @DatabaseName + ''',
       so.Name,
       si.Name,
       db_id(''' + @DatabaseName + '''),
       ips.object_id,
       ips.index_id,
       ips.index_type_desc,
       ips.alloc_unit_type_desc,
       ips.index_depth,
       ips.avg_fragmentation_in_percent,
       ips.fragment_count,
       avg_fragment_size_in_pages,
       ips.page_count,
       ips.record_count,
       case
         when ips.index_id = 0 then ''alter table [' + @DatabaseName + '].'' + ss.name + ''.['' + so.name + ''] rebuild with (online = on)''
         else ''alter index '' + si.name + '' on [' + @DatabaseName + '].'' + ss.name + ''.['' + so.name + ''] rebuild with (online = on)''
       end
  from sys.dm_db_index_physical_stats(db_id(''' + @DatabaseName + '''),null,null,null, ''' + @SampleMode + ''') ips
  join [' + @DatabaseName + '].sys.objects so  on so.object_id = ips.object_id
  join [' + @DatabaseName + '].sys.schemas ss  on ss.schema_id = so.schema_id
  join [' + @DatabaseName + '].sys.indexes si  on si.object_id = ips.object_id
                      and si.index_id  = ips.index_id
order by so.Name, ips.index_id
'

exec (@SQL)

Dựa trên nhận xét của JNK, tôi đã thay đổi truy vấn của mình để sử dụng SQL động. Nó hoạt động, tất nhiên. Tôi có một truy vấn riêng để tạo mã phân mảnh. Tôi sẽ cho nó chạy và nó trông như thế nào. Tuy nhiên, chấp nhận điều này là câu trả lời.
mdoyle

Một điều cần lưu ý ... điều này chạy trên SQL Server 2008R2 Enterprise Edition. "Xây dựng lại với (trực tuyến = bật)" không được hỗ trợ trên phiên bản tiêu chuẩn.
datagod

1
Thật ngọt ngào, tôi có đủ đại diện để bình chọn câu trả lời của bạn bây giờ. :-) Đây là một truy vấn khéo léo, nhưng tôi thích có riêng truy vấn tạo mã. Tôi thích chạy các kết quả thành văn bản và có thể cắt-dán vào một công việc. Giải pháp rất thanh lịch tất cả như nhau - cảm ơn!
mdoyle

8

Thay thế cho SQL động là SQLCMD , có thể được gọi từ dòng lệnh, bước công việc tác nhân, lệnh ghép ngắn Powershell Invoke-Sqlcmd hoặc được kích hoạt trong SSMS . Ví dụ của bạn trong cú pháp SQLCMD sẽ là:

:SETVAR DatabaseName MyDatabase

SELECT * FROM $(DatabaseName).sys.indexes;

Chế độ SQLCMD là một trong những tính năng mà tôi muốn biết trước đó. Tiện dụng trong rất nhiều tình huống.


1
Điều này cũng khá đơn giản và thanh lịch để thực hiện với PowerShell. Tôi thích cách tiếp cận của bạn, Mark. +1
Thomas Stringer

@Shark Điểm hay, tôi sẽ chỉnh sửa cmdlet powershell.
Mark Storey-Smith

Cũng là một giải pháp tốt, tôi cũng sẽ xem xét vấn đề này.
mdoyle

Điều này thật tuyệt, có lý do chính đáng tại sao điều này không được hỗ trợ trong TSQL không?
xương đòn

0

Thông thường rất khó để tham chiếu một tập hợp các bảng từ một thủ tục có trong một DB khác. Nếu bạn cài đặt thủ tục của mình trong Master, như một thủ tục hệ thống, thì nó có thể được sử dụng trong các bối cảnh DB khác mà không cố gắng tham khảo lại chính nó.

Tôi nghĩ rằng: nếu quy trình của bạn bắt đầu bằng 'sp_' thì nó sẽ hiển thị toàn cầu và nếu bạn xác định nó trong lược đồ 'sys.sp_%', thì nó có thể được sử dụng trong các bối cảnh DB khác.

Điều này sẽ cung cấp một cách khác để hoạt động trong nhiều DB mà không cần phải cắm DB_name một cách linh hoạt.

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.