Find broken objects in SQL Server

2020-01-29 04:23发布

Is there a tool that will find all objects in SQL Server (functions, procs, views) that cannot possibly work because they refer to objects that don't exist?

11条回答
狗以群分
2楼-- · 2020-01-29 04:51

The two previous solutions here are interesting, but both failed on my test databases.

The original Michael J Swart script produced a huge number of false positives for me, far too many to wade through. Rick V.'s solution here was better - the only false positives it gave were for cross-database references.

There's a comment on the Michael J Swart article by RaduSun which gives a solution that I can't yet break though! This is it, tweaked mildly for readability and my purposes, but credit to RaduSun for the logic.

SELECT 
    QuoteName(OBJECT_SCHEMA_NAME(referencing_id)) + '.' 
        + QuoteName(OBJECT_NAME(referencing_id)) AS ProblemObject,
    o.type_desc,
    ISNULL(QuoteName(referenced_server_name) + '.', '')
    + ISNULL(QuoteName(referenced_database_name) + '.', '')
    + ISNULL(QuoteName(referenced_schema_name) + '.', '')
    + QuoteName(referenced_entity_name) AS MissingReferencedObject
FROM
    sys.sql_expression_dependencies sed
        LEFT JOIN sys.objects o
            ON sed.referencing_id=o.object_id
WHERE
    (is_ambiguous = 0)
    AND (OBJECT_ID(ISNULL(QuoteName(referenced_server_name) + '.', '')
    + ISNULL(QuoteName(referenced_database_name) + '.', '')
    + ISNULL(QuoteName(referenced_schema_name) + '.', '')
    + QuoteName(referenced_entity_name)) IS NULL)
ORDER BY
    ProblemObject,
    MissingReferencedObject
查看更多
手持菜刀,她持情操
3楼-- · 2020-01-29 04:56

Your best bet is to start using a tool like Visual Studio Database Edition. It's role is to manage a database schema. One of the many things it will do is to throw an error when you attempt to build the database project and it contains broken objects. It will of course do much more than this. The tool is free to any user of Visual Studio Team Suite or Visual Studio Developer Edition.

查看更多
Anthone
4楼-- · 2020-01-29 04:58

I'm actually using sys.refreshmodule procedure now wrapped in a powershell script with the SQL Server Powershell add ins.

This works better because this handy little sys function gets rid of the CREATE vs ALTER stuff. Some other answers here use this approach as well, but I prefer this one that's wrapped in Powershell and maybe some will find it useful.

$server = "YourDBServer"
cls
Import-Module “sqlps” -DisableNameChecking

$databases = Invoke-Sqlcmd -Query "select name from sys.databases where name not in ('master', 'tempdb', 'model', 'msdb')" -ServerInstance $server
foreach ($db in $databases) {
    $dbName = $db.name
    $procedures = Invoke-Sqlcmd -Query "select SCHEMA_NAME(schema_id) as [schema], name from $dbName.sys.procedures" -ServerInstance $server
    foreach ($proc in $procedures) {
        if ($schema) {
            $shortName = $proc.schema + "." + $proc.name
            $procName =  $db.name + "." + $shortName
            try {
                $result = Invoke-Sqlcmd -Database $dbName -Query "sys.sp_refreshsqlmodule '$shortName'" -ServerInstance $server -ErrorAction Stop
                Write-Host "SUCCESS|$procName"
            }
            catch {
                $msg = $_.Exception.Message.Replace([Environment]::NewLine, ",")
                Write-Host "FAILED|$procName|$msg" -ForegroundColor Yellow
            }
        }
    }
}
查看更多
疯言疯语
5楼-- · 2020-01-29 04:59

Note the query in this thread finds missing objects, not invalid ones. 
SQL Server doesn't find a referencing object is invalid until you execute it.

Enhancement to that query to handle objects in other schemas as well as types:

SELECT
    '[' + OBJECT_SCHEMA_NAME(referencing_id) + '].[' + OBJECT_NAME(referencing_id) + ']' 
        AS [this sproc, UDF or VIEW...],
    isnull('[' + referenced_schema_name + '].', '') + '[' + referenced_entity_name + ']' 
        AS [... depends ON this missing entity name]
FROM 
    sys.sql_expression_dependencies
WHERE 
    is_ambiguous = 0 AND 
    (
        (
            [referenced_class_desc] = 'TYPE' and 
            TYPE_ID(
                isnull('[' + referenced_schema_name + '].', '') + 
                '[' + referenced_entity_name + ']'
            ) IS NULL
        ) or
        (   
            [referenced_class_desc] <> 'TYPE' and 
            OBJECT_ID(
                isnull('[' + referenced_schema_name + '].', '') + 
                '[' + referenced_entity_name + ']'
            ) IS NULL
        )
    )
ORDER BY 
    '[' + OBJECT_SCHEMA_NAME(referencing_id) + '].[' + OBJECT_NAME(referencing_id) + ']',
    isnull('[' + referenced_schema_name + '].', '') + '[' + referenced_entity_name + ']'
查看更多
地球回转人心会变
6楼-- · 2020-01-29 05:04

I wrote a script some years ago that will find Stored Procedures that won't compile by pulling the text of the proc and attempting to recompile it with a try/catch block. It's pretty simple and effective at finding at least procedures that can be dropped. You could easily expand it for views.

Note that you should only run this against a DEV or TEST environment since it's actually attempting to recompile the procedures.

SET NOCOUNT ON

DECLARE @ProcedureName VARCHAR(2048)
DECLARE @ProcedureBody VARCHAR(MAX)

DECLARE @RoutineName varchar(500)

DECLARE procCursor CURSOR STATIC FORWARD_ONLY READ_ONLY
 FOR
 SELECT
 --TOP 1
 SCHEMA_NAME(schema_id) + '.' + NAME AS ProcedureName,
 OBJECT_DEFINITION(o.[object_id]) AS ProcedureBody
 FROM sys.objects AS o
 WHERE o.[type] = 'P'
 ORDER BY o.[name]

OPEN procCursor
FETCH NEXT FROM procCursor INTO @ProcedureName, @ProcedureBody

WHILE @@FETCH_STATUS = 0
BEGIN
 -- Might have to play with this logic if you don't have discipline in your create statements
 SET @ProcedureBody = REPLACE(@ProcedureBody, 'CREATE PROCEDURE', 'ALTER PROCEDURE')

 BEGIN TRY
   EXECUTE(@ProcedureBody)
   PRINT @ProcedureName + ' -- Succeeded'
 END TRY
 BEGIN CATCH
   PRINT @ProcedureName + ' -- Failed: ' + ERROR_MESSAGE()
 END CATCH

 FETCH NEXT FROM procCursor INTO @ProcedureName, @ProcedureBody
END

CLOSE procCursor
DEALLOCATE procCursor

https://brettwgreen.wordpress.com/2012/12/04/find-stored-procedures-that-wont-compile/

查看更多
我只想做你的唯一
7楼-- · 2020-01-29 05:08

You may be interested in checking out the following articles:

You can test Michael J. Swart's solution as follows:

CREATE PROCEDURE proc_bad AS
    SELECT col FROM nonexisting_table
GO

SELECT
    OBJECT_NAME(referencing_id) AS [this sproc or VIEW...],
    referenced_entity_name AS [... depends ON this missing entity name]
FROM 
    sys.sql_expression_dependencies
WHERE 
    is_ambiguous = 0
    AND OBJECT_ID(referenced_entity_name) IS NULL
ORDER BY 
    OBJECT_NAME(referencing_id), referenced_entity_name;

Which returns:

+------------------------+------------------------------------------+
| this sproc or VIEW...  |  ... depends ON this missing entity name |
|------------------------+------------------------------------------|
| proc_bad               |  nonexisting_table                       |
+------------------------+------------------------------------------+
查看更多
登录 后发表回答