2017-03-31 94 views
1

我们目前正在参与一个数据迁移项目,为此我们必须分析数据的使用,这意味着我们需要弄清楚哪些是用来表和列,需要迁移,哪些数据已过时。 我们不仅拥有许多基于存储过程的SSRS报告,而且还有数百个(如果不是数千个)用于临时分析的TSQL脚本。几乎不可能用手分析它们。解析TSQL脚本并返回表和列使用

我在寻找解析这些脚本并返回脚本使用的数据的方法。我设法在EditPad中编写了一个从脚本中提取表格的宏,但是我没有对列做同样的处理。这里的主要问题是别名,CTE以及脚本中与其他命令区别的列名。

相较于简单的基于正则表达式的宏,SQL Server必须有其列由脚本中使用一个明确的想法 - >执行计划。 有什么方法可以将这种功能用于我们的目的?甚至更好:是否有任何第三方工具可以满足我们的需求?到目前为止,我找不到任何东西。

非常感谢您的任何建议!

+0

程序不是太糟糕,至少得到表,但列是另一回事。即使使用sys.sysdepends也只会让你看到对象。这些对象可以是表格,但它们也可以是函数,视图等,这些也必须进行分析。然后,当您进行临时查询时,几乎不可能精确地手动解析它。 –

+0

RedGate SQL Search具有影响分析功能,可以让您找到存储过程中引用列名称的位置。不知道它会帮助你的特别查询。 http://www.red-gate.com/products/sql-development/sql-search/ – mallan1121

回答

2

解析执行计划中的表和列可能是可能的,但这不是一件容易的事。 (我会看着这个帖子,以防有人说出来。)第三方工具可能要做到这一点,另一件需要注意的事情。根据我的经验,我认为这可能是不可行的,而不是你所需要的全部程度。

横向的方法:你可以安排对数据库“运行一切”,让你知道所有可能试图访问你的数据都被打?如果是这样的:

  • 创建数据库的副本。
  • 只包含尽可能少的数据以使查询正常工作。
  • (所以,无论是备份/恢复,或使用SSMS为“脚本出”数据库)
  • 配置的安全性,使得使用可以访问什么
  • 运行第一个查询的登录,它就会失败。确定哪些表和列它需要访问。授予,只有那些表和列的访问。
  • 运行一个查询,重复。
  • 赔率是可以运行查询的批次,并添加表/列集体
  • 保存通过首先启用已知/明显的表格
  • 一旦所有查询都可以成功运行,因为所有相关的表和列都已启用,您将拥有最小集合。

事情是...写了这么多,我看到很多潜在的警告,边缘案例和陷阱(完全取决于你要处理什么 - 视图怎么样?触发器?同义词?),我必须质疑是否值得努力。如果你确定会裁减掉一半的数据库,那就去做吧,但是如果减少10%,这可能不值得。 (对于减少10%,尽量只重命名最可疑的表,看看会发生什么。)

+0

非常感谢,如果我们无法开发自动化解决方案,这是一个很好的后备解决方案。 –

1

的部分答案:

基于this article,有可能使用PowerShell(或编译。Net语言)使用Microsoft.SqlServer.Management.SqlParser为Microsoft工具使用的SQL语句生成分析树。

[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.Management.SqlParser") | Out-Null 
$ParseOptions = New-Object Microsoft.SqlServer.Management.SqlParser.Parser.ParseOptions 
$ParseOptions.BatchSeparator = 'GO' 
$ParseOptions.CompatibilityLevel = [Microsoft.SqlServer.Management.SqlParser.Common.DatabaseCompatibilityLevel]::Current 
$ParseOptions.IsQuotedIdentifierSet = $true 
$ParseOptions.TransactSqlVersion= [Microsoft.SqlServer.Management.SqlParser.Common.TransactSqlVersion]::Current 

set-psdebug -strict 

#$SQL=get-content $Args[0] |foreach-object{"$_`n"} 

$SQL = "SELECT c.COLUMN_NAME, 
     c.TABLE_NAME, 
     t.TABLE_SCHEMA, 
     t.TABLE_TYPE, 
     t.TABLE_NAME AS t2 
FROM INFORMATION_SCHEMA.TABLES AS t 
JOIN INFORMATION_SCHEMA.COLUMNS AS c 
ON c.TABLE_NAME = t.TABLE_NAME 
AND c.TABLE_SCHEMA = t.TABLE_SCHEMA 
AND c.TABLE_CATALOG = t.TABLE_CATALOG 
" 

$Script=[Microsoft.SqlServer.Management.SqlParser.Parser.Parser]::Parse($SQL, $ParseOptions) 

$flags = [System.Reflection.BindingFlags]::Instance -bor [System.Reflection.BindingFlags]::NonPublic 
$Script.GetType().GetProperty("Script", $flags).GetValue($Script).Xml 

我有本地版本的SSMS 2016和SQL Server 2014安装,这工作没有安装任何其他。

这仍然留下了很多工作要解释树,但你可能能够利用它。

+0

很好,非常感谢,这看起来很有希望。我们一定会试试这个。 –

0

我的一位同事曾使用XML解析查询执行计划的聪明的想法:

执行计划已经被保存为XML,然后过滤网站上,以减少层级深度/号码,其必须不大于128:

http://xmltoolbox.appspot.com/

1. Paste the XML 
2. Add Column Reference as a filter 
3. Format xml 
4. Save it again as flatfile 

过滤的XML可以读取和在SQL处理:

DECLARE @xml xml = (
       SELECT CAST(BulkColumn AS XML) FROM OPENROWSET(  
       BULK 'c:\temp\Herkunftsselect_filtered.xml',  
       SINGLE_BLOB) AS ExecPlan 
   ); 

WITH XMLNAMESPACES ('http://schemas.microsoft.com/sqlserver/2004/07/showplan' AS SP) 
SELECT DISTINCT 
       'Database' = n.xml.value('./@Database','nvarchar(100)'), 
       'Schema' =          n.xml.value('./@Schema','nvarchar(100)'), 
       'Tabelle' =         n.xml.value('./@Table','nvarchar(100)'), 
       'Alias' =           n.xml.value('./@Alias','nvarchar(100)'), 
       'Column' =          n.xml.value('./@Column','nvarchar(100)') 
FROM @xml.nodes('/Root/SP:ColumnReference') n(xml) 
WHERE n.xml.value('./@Column','nvarchar(100)') NOT LIKE 'Expr%' 
  AND n.xml.value('./@Column','nvarchar(100)') NOT LIKE 'Chk%' 
  AND n.xml.value('./@Column','nvarchar(100)') NOT LIKE 'Bitmap%' 
  AND n.xml.value('./@Column','nvarchar(100)') NOT LIKE 'IsBaseRow%' 
  AND n.xml.value('./@Column','nvarchar(100)') NOT LIKE 'Union%' 
  AND n.xml.value('./@Column','nvarchar(100)') NOT LIKE 'Segment%' 

ORDER BY 1,2,3,4,5 

现在,唯一缺少的部分是如何完全自动化进程以遍历脚本文件,生成执行计划,过滤xml并运行查询。我的同事考虑的一种方式可能是将所有脚本文件合并成一个大文件(循环遍历文件并追加它们),以便手动过程只需要完成一次。