2010-02-24 1 views
22

Есть ли инструмент, который найдет все объекты в SQL Server (функции, procs, views), которые не могут работать, потому что они относятся к объектам, которые не существуют?Найти разбитые объекты в SQL Server

+1

Там есть фундаментальные проблемы с этим, если у вас есть какие-либо динамический SQL - что потенциально может обратиться к любому объекту на всех, особенно в сочетании с INFORMATION_SCHEMA. Справедливо ли считать, что использование динамического SQL достаточно редко, что это не проблема? –

+1

Я был бы очень рад, если бы нашел те, которые, как известно, отсутствуют. Динамический SQL - это тема, с которой я сейчас не готов разбираться. –

ответ

2

Я на самом деле с помощью sys.refreshmodule процедуры Теперь, завернутое в Powershell скрипт с SQL Server Powershell добавить модули.

Это работает лучше, потому что эта удобная функция sys избавляется от материала CREATE vs ALTER. Некоторые другие ответы здесь также используют этот подход, но я предпочитаю этот, который завернут в Powershell, и, возможно, некоторые из них посчитают это полезным.

$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 
      } 
     } 
    } 
} 
17

Вы можете быть заинтересованы в проверке из следующих статей:

Вы можете протестировать решение Майкла Дж смуглый, как показано ниже:

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; 

Какие возвращается:

+------------------------+------------------------------------------+ 
| this sproc or VIEW... | ... depends ON this missing entity name | 
|------------------------+------------------------------------------| 
| proc_bad    | nonexisting_table      | 
+------------------------+------------------------------------------+ 
+0

Это выглядит действительно многообещающим. Однако есть небольшая ошибка в предложении where. Он нуждается в «И ISNULL (sys.sql_expression_dependencies.referended_database_name, 'XXX') = 'XXX' ", если вы используете запросы с кросс-базами. –

+1

Я одобряю это решение :-) Помните, что он полагается на sys.sql_expression_dependencies, который является новым представлением в SQL Server 2008. –

+1

Это производит a * lot * ложных срабатываний в моих тестовых базах данных - может быть сущностями в нескольких схемах, может быть использование синонимов. Другой скрипт в ответе здесь и сценарий в комментарии № 5 ссылки Michael J Swart обе дают результаты, которые выглядят лучше, но не совсем согласны - пройдут результаты и найдут, почему, и которым можно доверять! – eftpotrm

0

Лучше всего начать с использования такого инструмента, как Visual Studio Database Edition. Роль заключается в управлении схемой базы данных. Одна из многих вещей, которые он сделает, - это выбросить ошибку при попытке создать проект базы данных и содержать сломанные объекты. Конечно, это будет намного больше. Этот инструмент является бесплатным для любого пользователя Visual Studio Team Suite или Visual Studio Developer Edition.

+0

Увы, это не сработает. Этот продукт не обрабатывает круговые ссылки между базами данных. –

6

SQL Prompt 5 У Red Hat Software есть Найти недействительные объекты функция, которая может быть полезна в этой ситуации. Инструмент проходит через базу данных, обнаруживая объекты, которые будут выдавать ошибку при выполнении, которая звучит именно так, как вы хотите.

Вы можете бесплатно скачать 14-дневную пробную версию, чтобы вы могли попробовать и посмотреть, помогает ли она.

Пол Стивенсон
SQL Manager
Red Gate Software Prompt Project

+0

[анонимные комментарии пользователей] (http://stackoverflow.com/spected-edits/202231), что ваш инструмент не работает должным образом, когда функция отсутствует (что, я думаю, было бы лучше, как отчет об ошибке) – Rup

0

Примечание запрос в этой теме находит отсутствующие объекты, а не недопустимых.  
SQL Server не обнаруживает, что ссылочный объект недействителен, пока вы его не выполнили.

Enhancement для этого запроса для обработки объектов в других схемах, а также типов:

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 + ']' 
+0

Это создавая ложный позитив для меня, когда у вас есть ссылка на перекрестный БД, извините. – eftpotrm

6

Две предыдущие решения здесь интересны, но оба потерпели неудачу на моих тестовых баз данных.

Оригинальный сценарий Майкла J Swart произвел огромное количество ложных срабатываний для меня, слишком много, чтобы пробраться. Решение Рика V. здесь было лучше - единственные ложные срабатывания, которые он давал, были для ссылок на разные базы данных.

Есть комментарий к статье Михаэля J Swart от RaduSun, которая дает решение, которое я пока не могу сломать! Это он, мягко изменился для удобочитаемости и моих целей, но приложил к RaduSun кредит за логику.

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 
+0

Это замечательно, за исключением того, что он не обрабатывает ссылки на пользовательские типы. Для быстрого и грязного исправления для себя я просто добавил 'AND NOT EXISTS (SELECT * FROM sys.types WHERE types.name = referenced_entity_name И types.schema_id = ISNULL (SCHEMA_ID (referenced_schema_name), SCHEMA_ID ('dbo'))) 'в' WHERE', но, вероятно, лучший способ. – siride

+0

Спасибо siride за то, что он расширил его, чтобы обработать это, у меня не было никаких UDT, чтобы проверить его на :-) – eftpotrm

+0

Я использовал этот запрос некоторое время, пока мы не обновили до SQL 2016. Теперь он сообщает о каждом триггете как недействительном из-за ссылки на таблицы INSERTED и DELETED –

4
/* 
modified version of script from http://michaeljswart.com/2009/12/find-missing-sql-dependencies/ 
Added columns for object types & generated refresh module command... 
filter out user-define types: http://stackoverflow.com/questions/2330521/find-broken-objects-in-sql-server 

*/

SELECT TOP (100) PERCENT 
    QuoteName(OBJECT_SCHEMA_NAME(referencing_id)) + '.' + QuoteName(OBJECT_NAME(referencing_id)) AS [this Object...], 
     o.type_desc, 
    ISNULL(QuoteName(referenced_server_name) + '.', '') 
    + ISNULL(QuoteName(referenced_database_name) + '.', '') 
    + ISNULL(QuoteName(referenced_schema_name) + '.', '') 
    + QuoteName(referenced_entity_name) AS [... depends ON this missing entity name] 
    ,sed.referenced_class_desc 
    ,case when o.type_desc in('SQL_STORED_PROCEDURE' ,'SQL_SCALAR_FUNCTION' ,'SQL_TRIGGER' ,'VIEW') 
      then 'EXEC sys.sp_refreshsqlmodule ''' + QuoteName(OBJECT_SCHEMA_NAME(referencing_id)) + '.' + QuoteName(OBJECT_NAME(referencing_id)) + ''';' 
      else null 
     end as [Refresh SQL Module command] 
FROM sys.sql_expression_dependencies as 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) 
AND NOT EXISTS 
    (SELECT * 
    FROM sys.types 
    WHERE types.name = referenced_entity_name 
    AND types.schema_id = ISNULL(SCHEMA_ID(referenced_schema_name), SCHEMA_ID('dbo')) 
    ) 
ORDER BY [this Object...], 
[... depends ON this missing entity name] 
4

First query даст вам сломанные имя объектов включает в себя Stored Procedure, View, Scalar function, DML trigger, Table-valued-function типа

/* 
///////////// 
////ERROR//// 
///////////// 
All error will be listed if object is broken 
*/ 
DECLARE @AllObjectName TABLE (
    OrdinalNo INT IDENTITY 
    ,ObjectName NVARCHAR(MAX) 
    ,ObjectType NVARCHAR(MAX) 
    ,ErrorMessage NVARCHAR(MAX) 
    ) 

INSERT INTO @AllObjectName (
    ObjectName 
    ,ObjectType 
    ) 
SELECT '[' + SCHEMA_NAME(schema_id) + '].[' + NAME + ']' ObjectName 
    ,CASE [TYPE] 
     WHEN 'P' 
      THEN 'Stored Procedure' 
     WHEN 'V' 
      THEN 'View' 
     WHEN 'FN' 
      THEN 'Scalar function' 
     WHEN 'TR' 
      THEN 'DML trigger' 
     WHEN 'TF' 
      THEN 'Table-valued-function' 
     ELSE 'Unknown Type' 
     END 
FROM sys.objects 
WHERE [TYPE] IN (
     'P' 
     ,'V' 
     ,'FN' 
     ,'TR' 
     ,'TF' 
     ) 
ORDER BY NAME 

DECLARE @i INT = 1 
DECLARE @RowCount INT = (
     SELECT count(1) 
     FROM @AllObjectName 
     ) 
DECLARE @ObjectName VARCHAR(MAX) 

WHILE @i <= @RowCount 
BEGIN 
    BEGIN TRY 
     SET @ObjectName = (
       SELECT ObjectName 
       FROM @AllObjectName 
       WHERE OrdinalNo = @i 
       ) 

     EXEC sys.sp_refreshsqlmodule @ObjectName 
    END TRY 

    BEGIN CATCH 
     DECLARE @message VARCHAR(4000) 
      ,@xstate INT; 

     SELECT @message = ERROR_MESSAGE() 
      ,@xstate = XACT_STATE(); 

     IF @xstate = - 1 
      ROLLBACK; 

     UPDATE @AllObjectName 
     SET ErrorMessage = @message 
     WHERE OrdinalNo = @i 
    END CATCH 

    SET @i = @i + 1 
END 

SELECT ObjectName 
    ,ObjectType 
    ,ErrorMessage 
FROM @AllObjectName 
WHERE ErrorMessage IS NOT NULL 

И below one поиск неразрешенных ссылок .. Как правило, которое рассматривается как warning, все еще может привести к error иногда

/* 
///////////// 
///Warning/// 
///////////// 
Here all warning will come if object reference is not stated properly 
*/ 
SELECT TOP (100) PERCENT QuoteName(OBJECT_SCHEMA_NAME(referencing_id)) + '.' + QuoteName(OBJECT_NAME(referencing_id)) AS [this Object...] 
    ,o.type_desc 
    ,ISNULL(QuoteName(referenced_server_name) + '.', '') + ISNULL(QuoteName(referenced_database_name) + '.', '') + ISNULL(QuoteName(referenced_schema_name) + '.', '') + QuoteName(referenced_entity_name) AS [... depends ON this missing entity name] 
    ,sed.referenced_class_desc 
FROM sys.sql_expression_dependencies AS 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) 
    AND NOT EXISTS (
     SELECT * 
     FROM sys.types 
     WHERE types.NAME = referenced_entity_name 
      AND types.schema_id = ISNULL(SCHEMA_ID(referenced_schema_name), SCHEMA_ID('dbo')) 
     ) 
ORDER BY [this Object...] 
    ,[... depends ON this missing entity name] 

Спасибо @SQLMonger .. за предоставленную мне ключ, чтобы сделать First query, который был моим фактическим требованием

+0

Этот первый запрос PERFECT! Спасибо за это, это потрясающе! Я не могу поверить после того, сколько десятилетий MS все еще не построила нечто подобное. Я почти хочу взять этот запрос и завершить его и выяснить, как написать плагин SSMS! – eidylon

+0

@eidylon ... Это здорово ... я тоже создаю ... скоро будет обновление ... вот ссылка .... https://marketplace.visualstudio.com/items?itemName=MrMKM. Мастердата – Moumit

1

Я написал сценарий несколько лет назад, который найдет хранимые процедуры которые не будут компилироваться, вытягивая текст proc и пытаясь перекомпилировать его с помощью блока try/catch. Это довольно просто и эффективно при поиске как минимум процедур, которые можно отбросить. Вы можете легко расширить его для просмотра.

Обратите внимание, что вы должны запускать это только в среде DEV или TEST, поскольку на самом деле пытаетесь перекомпилировать процедуры.

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/

1

По состоянию на SQL Server 2008, намного более простой метод здесь:

SELECT OBJECT_NAME(referencing_id) AS 'object making reference' , 
     referenced_class_desc , 
     referenced_schema_name , 
     referenced_entity_name AS 'object name referenced' , 
     ( SELECT object_id 
      FROM sys.objects 
      WHERE name = [referenced_entity_name] 
     ) AS 'Object Found?' 
FROM sys.sql_expression_dependencies e 
     LEFT JOIN sys.tables t ON e.referenced_entity_name = t.name; 

Как упомянуто в источнике статьи (Microsoft MSDN Article on Finding Missing Dependencies), «A 'NULL' значение в 'Объект Найдено? столбец указывает, что объект не найден в sys.objects. "

Пример вывода:

╔═══════════════════════════════════════════════╦═══════════════════════╦════════════════════════╦═══════════════════════════════════════╦═══════════════╗ 
║   object making reference   ║ referenced_class_desc ║ referenced_schema_name ║  object name referenced   ║ Object Found? ║ 
╠═══════════════════════════════════════════════╬═══════════════════════╬════════════════════════╬═══════════════════════════════════════╬═══════════════╣ 
║ usvConversationsWithoutServerNotices   ║ OBJECT_OR_COLUMN  ║ dbo     ║ ConversationLinesWithID    ║ NULL   ║ 
║ usvFormattedConversationLines_WithSpeakerName ║ OBJECT_OR_COLUMN  ║ dbo     ║ ConversationLinesWithID    ║ NULL   ║ 
║ usvFormattedConversationLines_WithSpeakerName ║ OBJECT_OR_COLUMN  ║ dbo     ║ FormattedConversationLines_Cached  ║ NULL   ║ 
║ udpCheckForDuplicates       ║ OBJECT_OR_COLUMN  ║ dbo     ║ FormattedConversationLines_WithChatID ║ NULL   ║ 
║ usvFormattedConversationsCombined    ║ OBJECT_OR_COLUMN  ║ dbo     ║ GROUP_CONCAT_D      ║ 178099675  ║ 
║ usvSequenceCrossValidationSetStudents   ║ OBJECT_OR_COLUMN  ║ dbo     ║ usvSequenceCrossValidationSet   ║ 1406628054 ║ 
╚═══════════════════════════════════════════════╩═══════════════════════╩════════════════════════╩═══════════════════════════════════════╩═══════════════╝