需求
現(xiàn)在數(shù)據(jù)庫很老很大,表不多,200來個(gè),但數(shù)據(jù)量很大:最大的數(shù)據(jù)表2億6千萬條,每天增加50多w,925個(gè)存儲(chǔ)過程。
系統(tǒng)大,耦合度很高,牽一發(fā)而動(dòng)全身。人員變動(dòng)頻繁,接手的人員要在修改之前,就得花相當(dāng)長的時(shí)間來分析關(guān)聯(lián)性。
所以,印度資深系統(tǒng)分析員要求我在一個(gè)EXCEL文件中,把925個(gè)存儲(chǔ)過程的所有依賴的對(duì)象(表、函數(shù)、視圖、存儲(chǔ)過程等等)都列舉出來。
分析
手工逐個(gè)打開存儲(chǔ)過程去做,對(duì)寫軟件的人來說是很傻的事情,一般重復(fù)性工作,如果預(yù)計(jì)耗時(shí)超過3分鐘,我就會(huì)卷起袖子寫個(gè)代碼。
工作內(nèi)容有3部分:
1.獲取所有的存儲(chǔ)過程。我們可以用sysobjects這個(gè)系統(tǒng)表,它存儲(chǔ)了所有的表、存儲(chǔ)過程、視圖、函數(shù)等。其中存儲(chǔ)過程的xtype是P。另外說一下,如果是CLR存儲(chǔ)過程,類型是PC。
2. 獲取某存儲(chǔ)過程所依賴的對(duì)象,當(dāng)然是先google了。很久之前我就知道可以用系統(tǒng)存儲(chǔ)過程sp_depends來獲取,不過還是應(yīng)該看看還有什么更好的辦法。首先我發(fā)現(xiàn)這個(gè):http://www.mssqltips.com/tip.asp?tip=1294 。作者研究出4種辦法:INFORMATION_SCHEMA.ROUTINES/sp_depends/syscomments/sp_MSdependencies。其中就有我一直在用的sp_depends。其它辦法有的霸王硬上弓:用charindex來遍歷存儲(chǔ)過程內(nèi)容,或者用LIKE來判斷。。。。。我服了,寫代碼的風(fēng)格千差萬別,一些是[Foo],一些是Foo,而且不同的存儲(chǔ)過程名稱可能存在完全給另外一個(gè)包含,譬如Foo Foo1 AFoo等。
看完之后,我還是覺得使用sp_depends相對(duì)靠譜。為什么說“相對(duì)靠譜”呢?因?yàn)槲野l(fā)現(xiàn)它某些情況下也會(huì)沒有返回所有依賴的,這應(yīng)該是SQL Server的bug吧?如果要把所有依賴都找回來,你可以去修改被遺忘的引用存儲(chǔ)過程,隨便加個(gè)空行,運(yùn)行(就是保存結(jié)果),你會(huì)發(fā)現(xiàn)之前沒有顯示的依賴終于出現(xiàn)了。而且,sp_depends會(huì)輸出重復(fù)的記錄。。。所以我們在代碼中要剔除掉。
3. 既然是輸出到EXCEL文件,我們就需要找相應(yīng)的代碼。在這個(gè)網(wǎng)站已經(jīng)有很多EXCEL文件生成的代碼了,譬如NPOI。我最后采用了GemBox的,因?yàn)閴蜉p便。本來想用更輕便的MyXLS,但發(fā)現(xiàn)它不支持單背景色。當(dāng)然你也可以用別的,譬如XML格式的EXCEL文件,這是你個(gè)人的選擇了。
解決了上述的2個(gè)問題,我們就可以大干一場了。我還是采用VS2005+C#2.0,因?yàn)楣具是在用古老的XP搭配VS2005,鬼佬國家要求什么都正版,自然不會(huì)像我們在中國那樣隨便就升級(jí)到2010了。所以只能放棄LINQ,老老實(shí)實(shí)地寫冗余的代碼了。
以下代碼沒有什么特別的,都是循環(huán)所有存儲(chǔ)過程,然后循環(huán)每個(gè)存儲(chǔ)過程的依賴對(duì)象,然后排序輸出(先按照類型,然后按照名稱)。代碼也寫得很quick and dirty,10來分鐘的事情,不要跟代碼規(guī)范較真。
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Drawing;
using System.Data;
using System.Data.SqlClient;
using GemBox.Spreadsheet;
namespace SQLServerDocumenter
{
class Program
{
static void Main(string[] args)
{
if (args.Length == 0)
{
args = new string[3];
args[0] = "FooDB";
args[1] = "FooServer";
args[2] = "FooPassword";
}
string db = args[0];
string dataSource = args.Length > 1 ? args[1] : string.Empty;
string password = args.Length > 2 ? args[2] : string.Empty;
ExcelFile xls = new ExcelFile();
ExcelWorksheet sheet = xls.Worksheets.Add("Dictionary");
CellStyle typeStyle = new CellStyle(xls);
typeStyle.FillPattern.SetSolid(Color.Yellow);
typeStyle.Font.Color = Color.Black;
typeStyle.Font.Weight = ExcelFont.BoldWeight;
CellStyle nameStyle = new CellStyle(xls);
nameStyle.FillPattern.SetSolid(Color.DarkGray);
nameStyle.Font.Color = Color.Black;
nameStyle.Font.Weight = ExcelFont.BoldWeight;
CellStyle itemStyle = new CellStyle(xls);
itemStyle.FillPattern.SetSolid(Color.LightGray);
itemStyle.Font.Color = Color.Black;
itemStyle.Font.Weight = ExcelFont.BoldWeight;
北京 | 天津 | 上海 | 江蘇 | 山東 |
安徽 | 浙江 | 江西 | 福建 | 深圳 |
廣東 | 河北 | 湖南 | 廣西 | 河南 |
海南 | 湖北 | 四川 | 重慶 | 云南 |
貴州 | 西藏 | 新疆 | 陜西 | 山西 |
寧夏 | 甘肅 | 青海 | 遼寧 | 吉林 |
黑龍江 | 內(nèi)蒙古 |