在數據庫中,咱們除了存儲數據外,還存儲了大量的元數據。它們主要的做用就是描述數據庫怎麼創建、配置、以及各類對象的屬性等。本篇簡單介紹如何使用和查詢元數據,如何更有效的管理SQLServer 數據庫。 sql
對一些有經驗的數據庫開發和管理人員而言,元數據是很是有價值的。下面我會介紹一下簡單的原理,而後儘可能用代碼的方式直接說明,畢竟「talk is cheap show me the code 」。數據庫
每個關係型數據庫系統,好比SQL Server 必定要提供關於它的結構的信息,這些信息每每須要經過sql語法來查詢。一般這些信息被保存在指定數據表的結構中。這意味着數據庫中有兩種不一樣的表:一是用戶自定義的表和系統表或者視圖(包含元數據)。從SQL Server 2005開始,只有視圖能夠查詢了,不能直接看到數據表了。安全
這種系統表或者視圖的結合一般參考關係型數據庫理論的文獻叫作做爲系統目錄或者數據字典。架構
在數據庫內部,有一些系統表一直追蹤數據庫中發生的每一件事情。系統表存儲像表、活動、列、索引等事情。這些徹底符合Edgar Codd 的關係型數據庫試試的十三條準則直譯。這個準則就是定義動態在線目錄,它就是「關於數據的數據」,也叫做元數據。app
Edgar Codd 準則4, 描述以下:dom
‘The database description is represented at the logical level in the same way as ordinary data, so that authorized users can apply the same relational language to its interrogation as they apply to the regular data.’函數
翻譯:像普通數據同樣,在邏輯層的數據表達了對數據庫的描述,以便於受權用戶能應用相同的SQL語言來查詢元數據,就如同查詢常規數據同樣。工具
在SQL Server中,能夠經過系統視圖或者架構視圖直接訪問動態在線目錄,方便用戶更爲快捷的開發和管理數據庫。學習
由於咱們不能直接訪問,須要使用視圖和函數來看這些信息。只能看到你權限內的數據。有更好的方法在用戶數據庫中使用數據定義語言(DDL),這些DDL語句包括CREATE, DROP, ALTER, GRANT, DENY, REVOKE 和sp_rename statements 等。總有一種方法可使用DDL來修改視圖中的任何信息,即便並不老是顯而易見的。
關係型數據庫使用動態的系統視圖中的數據描述數據庫,可是目前還有沒有標準化。可是有一個包含在每一個數據庫內的架構能夠讀取這些信息:就是Information Schema。
不走運的是,這個架構不足以提供足夠信息,這意味着咱們須要使用SQL Server 系統數據庫的視圖和函數來補充信息。接下來須要解釋一些術語和技術,我會盡量少的細節足以讓你們輕鬆地理解這些示例
如圖所示,如何訪問元數據,及其接口
這個架構是一套視圖,視圖中是當前數據庫的信息。每個數據庫中都有這個架構,只能看到當前數據庫的對象信息。能夠直接訪問這些架構的數據在主要的關係型數據中。其中架構視圖不包含數據庫部署信息。
對於不一樣的關係型數據庫之間的處理工做這個架構尤爲重要。它們很是適合平常工做,例如在訪問錢檢查是否存在,可是若是須要詳細報告則會受到限制。他們還使用一種稍有不一樣的標準命名法:例如,數據庫被稱爲目錄,用戶定義的數據類型被稱爲「domain」。
以前看到MSDN上有人警告說不要使用INFORMATION_SCHEMA視圖來確認對象架構,我理解是由於SQL Server容許在不一樣的架構中有相同的表名字,所以當只有表名稱的時候會有混淆。因此我認爲儘管放心使用就行了。
兼容性視圖是維護元數據的視圖,在SQL Server 2005以前是有系統表支持的,而且只向後兼容。只在2005以後的版本支持對於某些系統表的查詢,例如分區表等,只有部分元數據或者特性是對用戶可見的。對於帶有不少用戶、羣組、角色或者2000版本數據類型的數據庫而言,使用兼容性視圖是有潛在風險的,由於視圖中有的列存儲了用戶的ID或者類型ID,可能會返回NULL或者觸發溢出。
目錄視圖提供了關於數據庫架構的信息。它們也被數據庫引擎本身自己使用,尤爲在查詢優化環節。所以這些視圖須要更高效的方式來獲取元數據。除了複製、備份、數據庫維護計劃或SQL Server代理目錄數據以外,全部元數據都經過這些編目視圖公開。
這些視圖用一種至關特殊的方式排列,SQL Server對象的共有信息都保存在sys.objects裏面。有許多派生視圖,好比外鍵、約束、服務隊列、表、視圖和過程,這些視圖用特定於被編目的對象類型的信息來補充通常的對象信息
並不是SQL Server元數據中的全部內容都是對象。例如,一個列、索引或分佈統計信息不是對象。一些如主鍵約束或擴展屬性有一個奇怪的兩面性,由於它們被被當作爲一個對象,當被強制鍵索引的實例化時,它就不是一個對象。有些對象(主要是約束)與另外一種類型的對象具備父/子關係;父即表。
數據層應用程序視圖被用於訪問註冊服務器信息。特殊版本的服務器和信息用來檢查這些版本是否漂移。這是一種做爲容易的檢查當前註冊數據庫版本的方式,直接用T-SQL查詢。
DMV通常用來調優,診斷問題和監控數據庫服務器狀態。最重要的做用就是提供了一種方式來查詢數據庫的使用信息。例如,不只查詢到索引,並且能夠查詢到使用量的排序和耗時等。
還有不少元數據函數,如object_name()或col_name(),它們提供關於當前數據庫中的模式做用域對象的信息。經過避免在元數據表達式中進行顯式鏈接,它們提供了獲取信息的捷徑,所以,當與編目視圖一塊兒使用時,它們能夠幫助您更快地獲取關於元數據的信息。
有許多存儲過程的主要功能是爲SQL Server的ODBC驅動程序提供元數據信息。當您創建ODBC鏈接時,該信息做爲數據對象的集合。可是,這些信息一般是可用的,而且能夠像任何其餘存儲過程同樣從SQL中使用。它們一般被認爲不如目錄視圖有用,由於存儲過程返回的結果必須使用INSERT插入一個表或者表變量中,須要使用INSERT ... EXECUTE 語法。
爲何元數據視圖和功能很重要?
元數據視圖和函數容許您搜索元數據,提供對數據庫報告和總結,找出誰有權限查看或改變什麼數據,讓你減小重複輸入,讓幾乎全部隱藏在SQL Server Management Studio的信息可查詢,使部署腳本更安全,更可靠,找出最近的改變或建立,快速處理一些函數或過程,肯定已註冊數據庫的版本,審計用於編碼實踐的數據庫代碼,發現重複索引而且容許減小低效的點擊操做。當與其餘SQL Server工具(如默認跟蹤和動態管理對象)結合使用時,使用強大的SQL腳本用於開發和管理數據庫是至關快速的。
元數據視圖和函數容許執行幾乎不可能執行的操做,例如查找依賴於指定的CLR用戶定義類型或別名類型的參數。
學習使用元數據視圖和函數的第一階段是收集從各類著名的數據源(如SQL Server Central)中使用它們的查詢。能夠在MSDN上查詢到。使用記錄工具保存這些查詢。若是它是一個用來保存註釋或片斷的工具,可讓您在任何地方輕鬆地獲取查詢,那麼它將會有所幫助。一段時間後,就能夠根據使用須要對這些查詢稍做修改。而後,不須要在object browser窗格中搜索表列表,您很快就能夠從集合中獲取適當的查詢,執行它,並快速獲取信息。
下面我會展現的例子都已經在2008和2012 兩個版本中測試。固然只用到了各自版本的最後一個版本更新後的數據庫。
下圖中展現了全部繼承sys.objects列的視圖。這意味着它們除了擁有這些列之外,還有列的對應類型。這是視圖全部的信息好比create_date也都來自sys.objects。
要列出數據庫中的全部視圖(存儲過程和外鍵),只需執行如下操做 …
SELECT object_schema_name(object_id)+'.'+name FROM sys.views; SELECT object_schema_name(object_id)+'.'+name FROM sys.procedures;
SELECT name AS Foreign_key,object_schema_name(parent_object_ID)+'.'+object_name(parent_object_ID) AS parent,
object_schema_name(referenced_object_ID)+'.'+object_name(referenced_object_ID) AS referenced
FROM sys.foreign_keys;
對於全部其餘的,您須要使用一個系統函數來過濾您想要的對象。下面的代碼提供了一些有用的示例。由於咱們只獲取對象的名稱,因此使用sys.objects,它具備全部數據庫對象共有的基本信息的視圖。若是咱們須要特定於特定類型對象的信息,好比主鍵是否具備系統生成的名稱,那麼您就必須爲該特定類型的對象使用視圖。
/* The Tables */ --數據庫中的全部用戶表 SELECT ob.name AS User_Table, Coalesce(ep.value, '') AS documentation FROM sys.objects AS ob LEFT OUTER JOIN sys.extended_properties AS ep ON ep.major_id = ob.object_id AND ep.class = 1 AND ep.minor_id = 0 WHERE ObjectProperty(ob.object_id, 'IsUserTable') = 1
/* The Views */ --視圖 SELECT ob.name AS ViewName, Coalesce(ep.value, '') AS documentation FROM sys.objects ob LEFT OUTER JOIN sys.extended_properties AS ep ON ep.major_id = ob.object_id AND ep.class = 1 AND ep.minor_id = 0 WHERE objectproperty(ob.object_id,'IsView')= 1 /* The Check Constraints */ --Check約束 SELECT objects.name AS Name_of_Check_Constraint, Object_Schema_Name(objects.parent_object_id) + '.' + Object_Name(objects.parent_object_id) AS parent, Coalesce(ep.value,'') AS documentation FROM sys.objects LEFT OUTER JOIN sys.extended_properties AS ep ON ep.major_id = objects.object_id AND ep.class=1 AND ep.name='MS_Description'--microsoft 公約 WHERE ObjectProperty(objects.object_id, 'IsCheckCnst') = 1 /* The Constraints */
SELECT --約束 objects.name AS Name_of_Constraint, --see all constraints and parent table Lower(Replace(type_desc,'_',' ')),--the type of constraint Object_Schema_Name(objects.parent_object_id) + '.' + Object_Name(objects.parent_object_id) AS parent, Coalesce(ep.value, '') AS documentation FROM sys.objects LEFT OUTER JOIN sys.extended_properties AS ep ON ep.major_id = objects.object_id AND ep.class = 1 AND ep.name = 'MS_Description' WHERE ObjectProperty(objects.object_id, 'IsConstraint') = 1; /* The Defaults */ --默認 SELECT objects.name, Coalesce(ep.value, '') AS documentation FROM sys.objects LEFT OUTER JOIN sys.extended_properties AS ep ON ep.major_id = objects.object_id AND ep.class = 1 AND ep.name = 'MS_Description' WHERE ObjectProperty(objects.object_id, 'IsDefault') = 1; /* The Default Constraints */ --數據庫及其父表中的全部默認約束 SELECT objects.name AS Name_of_Default_Constraint,--see all Default constraints and parent table Coalesce(ep.value,'') AS documentation, object_schema_name(objects.parent_object_id)+'.'+object_name(objects.parent_object_id) AS parent, Coalesce(EP_parent.value,'') AS documentation FROM sys.objects LEFT OUTER JOIN sys.extended_properties AS ep ON ep.major_id = objects.object_id AND ep.class = 1 AND ep.name = 'MS_Description' --the microsoft convention LEFT OUTER JOIN sys.extended_properties AS EP_parent ON ep.major_id = objects.parent_object_id AND ep.name = 'MS_Description' --the microsoft convention WHERE objectproperty(objects.object_id,'IsDefaultCnst')= 1; /* The Executables */ --數據庫中的全部可執行文件(過程、函數等) SELECT oe.name AS Name_Of_Executable, Replace(Lower(oe.type_desc), '_', ' ') AS Type_Of_Executable, Coalesce(EP.value, '') AS Documentation FROM sys.objects AS oe LEFT OUTER JOIN sys.extended_properties AS EP ON EP.major_id = oe.object_id AND EP.name = 'MS_Description' WHERE ObjectProperty(oe.object_id, 'IsExecuted') = 1; /* The Extended Stored Procedures */ --數據庫中的全部擴展存儲過程 SELECT oep.name AS Name_of_Extended_Procedure, Coalesce(EP.value, '') AS Documentation FROM sys.objects AS oep LEFT OUTER JOIN sys.extended_properties AS EP ON EP.major_id = oep.object_id AND EP.name = 'MS_Description' WHERE ObjectProperty(oep.object_id, 'IsExtendedProc') = 1; /* The Inline Functions */ --數據庫中的全部內聯函數 SELECT ilf.name AS Inline_function, Coalesce(EP.value, '') AS Documentation FROM sys.objects AS ilf LEFT OUTER JOIN sys.extended_properties AS EP ON EP.major_id = ilf.object_id AND EP.name = 'MS_Description' WHERE objectproperty(ilf.object_id,'IsInlineFunction')= 1; /* The Primary Keys */ --數據庫中的全部主鍵及其父表 SELECT pk.name AS Primary_key, Object_Schema_Name(pk.parent_object_id) + '.' + Object_Name(pk.parent_object_id) AS parent, Coalesce(EP.value, '') AS KeyDoc, Coalesce(EPParent.value, '') AS TableDoc FROM sys.objects AS pk LEFT OUTER JOIN sys.extended_properties AS EP ON EP.major_id = pk.object_id AND EP.name = 'MS_Description' LEFT OUTER JOIN sys.extended_properties AS EPParent ON EPParent.major_id = pk.parent_object_id AND EPParent.minor_id = 0 AND EPParent.name = 'MS_Description' WHERE ObjectProperty(pk.object_id, 'IsPrimaryKey') = 1; /* The Stored Procedures */ --數據庫中的全部存儲過程 SELECT sp.name AS Stored_procedure, Coalesce(EP.value, '') AS Documentation FROM sys.objects AS sp LEFT OUTER JOIN sys.extended_properties AS EP ON EP.major_id = sp.object_id AND EP.minor_id = 0 AND EP.name = 'MS_Description' WHERE ObjectProperty(sp.object_id, 'IsProcedure') = 1; /* The Queues */ --數據庫中的全部隊列 SELECT q.name AS QueueName, Coalesce(EP.value, '') AS Documentation FROM sys.objects AS q LEFT OUTER JOIN sys.extended_properties AS EP ON EP.major_id = q.object_id AND EP.name = 'MS_Description' WHERE ObjectProperty(q.object_id, 'IsQueue') = 1; /* The Rules */ --數據庫中的全部舊式規則 SELECT ru.name AS RuleName, --old-fashioned sybase-style rule Coalesce(EP.value, '') AS Documentation FROM sys.objects AS ru LEFT OUTER JOIN sys.extended_properties AS EP ON EP.major_id = ru.object_id AND EP.name = 'MS_Description' WHERE ObjectProperty(ru.object_id, 'IsRule') = 1; /* The Scalar Functions */ --數據庫中的全部標量函數。 SELECT sf.name AS Scalar_function, Coalesce(EP.value, '') AS Documentation FROM sys.objects AS sf LEFT OUTER JOIN sys.extended_properties AS EP ON EP.major_id = sf.object_id AND EP.name = 'MS_Description' WHERE ObjectProperty(sf.object_id, 'IsScalarFunction') = 1; /* The System Tables */ --據庫中的全部系統表 SELECT st.name AS System_table, Coalesce(EP.value, '') AS Documentation FROM sys.objects AS st LEFT OUTER JOIN sys.extended_properties AS EP ON EP.major_id = st.object_id AND EP.name = 'MS_Description' WHERE ObjectProperty(st.object_id, 'IsSystemTable') = 1; --數據庫中的全部表,包括系統表 SELECT at.name AS TableName, Lower(Replace(type_desc,'_',' ')),--約束的類型 Coalesce(EP.value, '') AS Documentation FROM sys.objects AS at LEFT OUTER JOIN sys.extended_properties AS EP ON EP.major_id = at.object_id AND EP.name = 'MS_Description' WHERE ObjectProperty(at.object_id, 'IsTable') = 1; /* The TVFs*/ --數據庫中的全部表值函數 SELECT tvf.name AS Table_Valued_Function, Coalesce(EP.value, '') AS Documentation FROM sys.objects AS tvf LEFT OUTER JOIN sys.extended_properties AS EP ON EP.major_id = tvf.object_id AND EP.name = 'MS_Description' --the microsoft convention WHERE ObjectProperty(tvf.object_id, 'IsTableFunction') = 1; --數據庫及其全部觸發器。 SELECT tr.name AS TriggerName, Object_Schema_Name(tr.parent_object_id) + '.' + Object_Name(tr.parent_object_id) AS parent, Coalesce(EP.value, '') AS TriggerDoc, Coalesce(EPParent.value, '') AS TableDoc FROM sys.objects AS tr LEFT OUTER JOIN sys.extended_properties AS EP ON EP.major_id = tr.object_id AND EP.name = 'MS_Description' LEFT OUTER JOIN sys.extended_properties AS EPParent ON EPParent.major_id = tr.parent_object_id AND EPParent.minor_id = 0 AND EPParent.name = 'MS_Description' WHERE ObjectProperty(tr.object_id, 'IsTrigger') = 1; /* The Unique Constraints */ --數據庫及其父表中的全部唯一約束 SELECT uc.name AS Unique_constraint,--全部惟一的約束 object_schema_name(uc.parent_object_id)+'.'+object_name(uc.parent_object_id) AS parent, Coalesce(EP.value, '') AS ConstraintDoc, Coalesce(EPParent.value, '') AS TableDoc FROM sys.objects AS uc LEFT OUTER JOIN sys.extended_properties AS EP ON EP.major_id = uc.object_id AND EP.name = 'MS_Description' LEFT OUTER JOIN sys.extended_properties AS EPParent ON EPParent.major_id = uc.parent_object_id AND EPParent.minor_id = 0 AND EPParent.name = 'MS_Description' WHERE objectproperty(uc.object_id,'IsUniqueCnst')= 1;
固然咱們也能夠調整這些語句來方便咱們的精確查找,好比:
--數據庫中的全部視圖在過去兩週內被修改的有:
SELECT name AS ViewName, convert(char(11),modify_date,113) FROM sys.objects WHERE objectproperty(OBJECT_ID,'IsView')= 1 AND modify_date > dateadd(week,-2, GetDate());
--上個月建立的全部對象的名稱和類型
SELECT coalesce(object_schema_name(obj.object_ID)+'.','')+obj.name AS ObjectName, convert(varchar(30),lower(replace(type_desc,'_',' '))) FROM sys.objects obj WHERE create_date > dateadd(month,-1, GetDate());
--DBO架構中全部基本對象的名稱和類型
SELECT coalesce(object_schema_name(obj.object_ID)+'.','')+obj.name AS ObjectName, convert(varchar(30),lower(replace(type_desc,'_',' '))) as ObjectType FROM sys.objects obj WHERE parent_object_ID=0 AND schema_ID = schema_ID('dbo');
如上,到這級別簡單實用足夠了。們已經介紹了通常的理論,並介紹了查找數據庫中的內容的基本方法。在下一篇中我將會深刻介紹觸發器而且找到有效信息的排序以便於能夠經過系統視圖從動態在線目錄中收集的有用信息。