การอ้างอิงฐานข้อมูลโดยทางโปรแกรมผ่าน T-SQL


11

ฉันกำลังเขียนขั้นตอนการจัดเก็บที่ใช้ชื่อฐานข้อมูลเป็นอาร์กิวเมนต์และส่งกลับตารางของดัชนีของฐานข้อมูลและระดับการกระจายตัวของพวกเขา ขั้นตอนการจัดเก็บนี้จะอยู่ในฐานข้อมูล DBA ของเรา (ฐานข้อมูลที่มีตารางที่ DBA ใช้สำหรับการตรวจสอบและปรับปรุงสิ่งต่าง ๆ ) ระบบที่เป็นปัญหาคือ SQL Server 2008 R2 ทั้งหมดหากมีความแตกต่าง

ฉันมีการสืบค้นพื้นฐานแล้ว แต่ฉันพยายามหาชื่อจริงของดัชนี เพื่อความรู้ที่ดีที่สุดของฉันข้อมูลนั้นจะอยู่ในมุมมอง sys.indexes ของแต่ละคน ปัญหาเฉพาะของฉันพยายามอ้างอิงที่ดูโดยทางโปรแกรมจากกระบวนงานที่เก็บไว้ของฐานข้อมูลอื่น

เพื่อแสดงให้เห็นว่านี่เป็นส่วนของแบบสอบถามที่มีปัญหา:

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

แบบสอบถามทำงานได้ดีเมื่อดำเนินการจากฐานข้อมูลที่ระบุโดย @db_id เนื่องจากใช้มุมมอง sys.indexes ที่เหมาะสม ถ้าฉันพยายามเรียกสิ่งนี้จากฐานข้อมูล DBA ทุกอย่างจะเป็นโมฆะเนื่องจากมุมมอง sys.indexes มีไว้สำหรับฐานข้อมูลที่ไม่ถูกต้อง

โดยทั่วไปฉันต้องทำสิ่งนี้:

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

หรือ

USE @db_name;

ฉันได้ลองเปลี่ยนฐานข้อมูลหรืออ้างอิงฐานข้อมูลอื่นโดยใช้การรวมสตริงเข้าด้วยกันและฟังก์ชัน OBJECT_NAME / OBJECT_ID / DB_ID และดูเหมือนว่าจะไม่มีอะไรทำงาน ฉันขอขอบคุณแนวคิดใด ๆ ที่ชุมชนอาจมี แต่สงสัยว่าฉันจะต้องปรับกระบวนการจัดเก็บนี้ใหม่เพื่อให้อยู่ในฐานข้อมูลแต่ละรายการ

ขอบคุณล่วงหน้าสำหรับคำแนะนำใด ๆ


1
คุณจะต้องใช้ SQL แบบไดนามิกสำหรับนี้ฉันสงสัยว่า ...
JNK

คำตอบ:


10

Dynamic SQL มีประโยชน์สำหรับงานบริหารประเภทนี้ นี่คือตัวอย่างจากขั้นตอนการจัดเก็บที่ฉันเขียนซึ่งไม่เพียง แต่จะได้รับการจัดเรียงข้อมูลระดับ แต่ยังสร้างรหัสเพื่อทำการจัดเรียงข้อมูล:

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 ฉันเปลี่ยนแบบสอบถามของฉันเพื่อใช้ไดนามิก SQL มันใช้งานได้แน่นอน ฉันมีแบบสอบถามแยกต่างหากเพื่อสร้างรหัสการจัดเรียงข้อมูล ฉันจะให้มันวิ่งและดูว่า อย่างไรก็ตามการยอมรับสิ่งนี้เป็นคำตอบ
mdoyle

สิ่งหนึ่งที่ควรทราบ ... สิ่งนี้ทำงานบน SQL Server 2008R2 Enterprise Edition ไม่รองรับ "การสร้างใหม่ด้วย (ออนไลน์ = บน)" ในรุ่นมาตรฐาน
datagod

1
น่ารักฉันมีตัวแทนมากพอที่จะโหวตคำตอบของคุณตอนนี้ :-) นี่เป็นแบบสอบถามที่ลื่นไหล แต่ฉันชอบแยกแบบสอบถามที่สร้างรหัสออกมา ฉันชอบใช้ผลลัพธ์เป็นข้อความและสามารถตัดแปะลงในงานได้ ทางออกที่งดงามมากเหมือนกันทั้งหมด - ขอบคุณ!
mdoyle

8

ทางเลือกที่จะแบบไดนามิก SQL เป็นSQLCMDซึ่งสามารถเรียกจากบรรทัดคำสั่งขั้นตอนงานของ บริษัท ตัวแทนที่เรียก-Sqlcmd Powershell cmdlet หรือเปิดใช้งานในSSMS ตัวอย่างของคุณในไวยากรณ์ SQLCMD จะเป็น:

:SETVAR DatabaseName MyDatabase

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

โหมด SQLCMD เป็นหนึ่งในคุณสมบัติเหล่านั้นที่ฉันหวังว่าฉันจะรู้ก่อนหน้านี้ มีประโยชน์ในหลาย ๆ สถานการณ์


1
นี่เป็นวิธีที่ง่ายและสง่างามที่จะทำให้สำเร็จด้วย PowerShell ฉันชอบแนวทางของคุณมาร์ค +1
Thomas Stringer

@Shark จุดดีฉันจะแก้ไข powershell cmdlet ใน
Mark Storey-Smith

นอกจากนี้ยังเป็นทางออกที่ดีฉันจะพิจารณาเรื่องนี้เช่นกัน
mdoyle

นี่เป็นสิ่งที่ดีมีเหตุผลที่ดีที่ไม่รองรับ TSQL หรือไม่
tbone

0

โดยปกติจะเป็นการยากที่จะอ้างอิงชุดตารางหนึ่งชุดจากกระบวนงานที่อยู่ในฐานข้อมูลอื่น หากคุณติดตั้งโพรซีเดอร์ใน Master เป็นโพรซีเดอร์ระบบก็สามารถใช้ในบริบท DB อื่น ๆ ได้โดยไม่ต้องอ้างอิงกลับไปเอง

ฉันคิดว่า: หากโพรซีเดอร์ของคุณเริ่มต้นด้วย 'sp_' มันจะปรากฏอย่างเป็นสากลและถ้าคุณกำหนดใน schema 'sys.sp_%' คุณสามารถใช้มันในบริบท DB อื่น ๆ ได้

สิ่งนี้จะให้วิธีอื่นในการทำงานในหลาย ๆ ฐานข้อมูลโดยไม่ต้องเชื่อมต่อกับ DB_name แบบไดนามิก

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.