T-SQL ile programlı veritabanı referansı


11

Bir argüman olarak bir veritabanı adı alır ve bu veritabanının dizinleri ve parçalanma düzeyi bir tablo döndüren bir saklı yordam yazıyorum. Bu saklı yordam DBA veritabanımızda (DBA'ların bir şeyleri izlemek ve optimize etmek için kullandığı tabloları içeren DB) yaşayacaktır. Bir fark yaratırsa söz konusu sistemlerin tümü SQL Server 2008 R2'dir.

Ben temel sorgu çalıştı, ama dizinlerin gerçek isimlerini sağlamaya çalışırken takılıyorum. Bildiğim kadarıyla, bu bilgi her bireyin sys.indexes görünümünde bulunur. Benim özel sorun, bu görünümü başka bir veritabanının saklı yordamından programsal olarak başvurmaya çalışıyor.

Açıklamak gerekirse, bu sorgunun söz konusu kısmıdır:

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

Uygun sys.indexes görünümünü kullandığından, sorgu @db_id tarafından tanımlanan veritabanından yürütüldüğünde iyi çalışır. Eğer bunu DBA veritabanından çağırmaya çalışırsam, sys.indexes görünümü yanlış veritabanı için olduğu gibi, hepsi boş kalır.

Daha genel anlamda, böyle bir şey yapabilmem gerekiyor:

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

veya

USE @db_name;

Dize birleştirme ve OBJECT_NAME / OBJECT_ID / DB_ID işlevlerinin birleşimlerini kullanarak veritabanlarını değiştirmeyi veya diğer veritabanlarına başvurmayı denedim ve hiçbir şey işe yaramıyor. Topluluğun sahip olabileceği fikirleri takdir ediyorum, ancak her bir veritabanında yer almak için bu saklı yordamı yeniden düzeltmek zorunda kalacağından şüpheleniyorum.

Önerileriniz için şimdiden teşekkür ederiz.


1
Şüphelendiğim için dinamik SQL kullanmanız gerekecek ...
JNK

Yanıtlar:


10

Dinamik SQL, bu tür yönetim görevleri için kullanışlıdır. İşte birleştirme işlemi sadece birleştirme düzeyleri almak değil, aynı zamanda birleştirme yapmak için kod üretir yazdı bir yordam:

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)

JNK'nin yorumuna dayanarak dinamik SQL kullanmak için sorgumu değiştirdim. Elbette işe yarıyor. Birleştirme kodu oluşturmak için ayrı bir sorgu var. Ben bunu deneyeceğim ve nasıl göründüğünü. Ancak bunu cevap olarak kabul etmek.
mdoyle

Dikkat edilmesi gereken bir şey ... bu SQL Server 2008R2 Enterprise Edition'da çalışır. "Yeniden oluştur (çevrimiçi = açık)" standart sürümde desteklenmez.
datagod

1
Tatlým, cevabýný artýk oylamaya yetecek kadar temsilcim var. :-) Bu kaygan bir sorgu, ama kod üreten sorgu ayrı olması gibi. Sonuçları metne aktarmayı ve bir işe kesip yapıştırabilmeyi seviyorum. Çok zarif bir çözüm aynı - teşekkürler!
mdoyle

8

Dinamik SQL alternatiftir SQLCMD komut satırı, bir ajan iş adımında, çağrılabilir, ınvoke SQLCmd Powershell cmdlet'ine veya etkinleştirilmiş SSMS . SQLCMD sözdizimindeki örneğiniz:

:SETVAR DatabaseName MyDatabase

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

SQLCMD modu, daha önce bilseydim keşke bu özelliklerden biridir. Birçok durumda kullanışlı.


1
Bu aynı zamanda PowerShell ile başarmak için oldukça basit ve zariftir. Yaklaşımını seviyorum Mark. +1
Thomas Stringer

@Shark İyi bir nokta, powershell cmdlet'ini düzenleyeceğim.
Mark Storey-Smith

Ayrıca iyi bir çözüm, buna da bakacağım.
mdoyle

Bu güzel, bunun TSQL'de desteklenmemesinin iyi bir nedeni var mı?
tbone

0

Farklı bir DB'de bulunan bir yordamdan bir tablo kümesine başvurmak genellikle zordur. Prosedürünüzü Master'a bir sistem prosedürü olarak kurarsanız, kendisine geri başvurmaya çalışmadan diğer DB bağlamlarında kullanılabilir.

Bence: prosedürünüz 'sp_' ile başlıyorsa, o zaman evrensel olarak görünür hale gelir ve 'sys.sp_%' şemasında tanımlarsanız, diğer DB bağlamlarında kullanılabilir.

Bu, DB_adı dinamik olarak takmak zorunda kalmadan birden çok DB'de çalışmak için alternatif bir yol sağlar.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.