Есть ли инструмент, который найдет все объекты в SQL Server (функции, procs, views), которые не могут работать, потому что они относятся к объектам, которые не существуют?Найти разбитые объекты в SQL Server
ответ
Я на самом деле с помощью 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
}
}
}
}
Вы можете быть заинтересованы в проверке из следующих статей:
Вы можете протестировать решение Майкла Дж смуглый, как показано ниже:
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 |
+------------------------+------------------------------------------+
Это выглядит действительно многообещающим. Однако есть небольшая ошибка в предложении where. Он нуждается в «И ISNULL (sys.sql_expression_dependencies.referended_database_name, 'XXX') = 'XXX' ", если вы используете запросы с кросс-базами. –
Я одобряю это решение :-) Помните, что он полагается на sys.sql_expression_dependencies, который является новым представлением в SQL Server 2008. –
Это производит a * lot * ложных срабатываний в моих тестовых базах данных - может быть сущностями в нескольких схемах, может быть использование синонимов. Другой скрипт в ответе здесь и сценарий в комментарии № 5 ссылки Michael J Swart обе дают результаты, которые выглядят лучше, но не совсем согласны - пройдут результаты и найдут, почему, и которым можно доверять! – eftpotrm
Лучше всего начать с использования такого инструмента, как Visual Studio Database Edition. Роль заключается в управлении схемой базы данных. Одна из многих вещей, которые он сделает, - это выбросить ошибку при попытке создать проект базы данных и содержать сломанные объекты. Конечно, это будет намного больше. Этот инструмент является бесплатным для любого пользователя Visual Studio Team Suite или Visual Studio Developer Edition.
Увы, это не сработает. Этот продукт не обрабатывает круговые ссылки между базами данных. –
SQL Prompt 5 У Red Hat Software есть Найти недействительные объекты функция, которая может быть полезна в этой ситуации. Инструмент проходит через базу данных, обнаруживая объекты, которые будут выдавать ошибку при выполнении, которая звучит именно так, как вы хотите.
Вы можете бесплатно скачать 14-дневную пробную версию, чтобы вы могли попробовать и посмотреть, помогает ли она.
Пол Стивенсон
SQL Manager
Red Gate Software Prompt Project
[анонимные комментарии пользователей] (http://stackoverflow.com/spected-edits/202231), что ваш инструмент не работает должным образом, когда функция отсутствует (что, я думаю, было бы лучше, как отчет об ошибке) – Rup
Примечание запрос в этой теме находит отсутствующие объекты, а не недопустимых.
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 + ']'
Это создавая ложный позитив для меня, когда у вас есть ссылка на перекрестный БД, извините. – eftpotrm
Две предыдущие решения здесь интересны, но оба потерпели неудачу на моих тестовых баз данных.
Оригинальный сценарий Майкла 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
Это замечательно, за исключением того, что он не обрабатывает ссылки на пользовательские типы. Для быстрого и грязного исправления для себя я просто добавил '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
Спасибо siride за то, что он расширил его, чтобы обработать это, у меня не было никаких UDT, чтобы проверить его на :-) – eftpotrm
Я использовал этот запрос некоторое время, пока мы не обновили до SQL 2016. Теперь он сообщает о каждом триггете как недействительном из-за ссылки на таблицы INSERTED и DELETED –
/*
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]
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
, который был моим фактическим требованием
Этот первый запрос PERFECT! Спасибо за это, это потрясающе! Я не могу поверить после того, сколько десятилетий MS все еще не построила нечто подобное. Я почти хочу взять этот запрос и завершить его и выяснить, как написать плагин SSMS! – eidylon
@eidylon ... Это здорово ... я тоже создаю ... скоро будет обновление ... вот ссылка .... https://marketplace.visualstudio.com/items?itemName=MrMKM. Мастердата – Moumit
Я написал сценарий несколько лет назад, который найдет хранимые процедуры которые не будут компилироваться, вытягивая текст 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/
По состоянию на 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 ║
╚═══════════════════════════════════════════════╩═══════════════════════╩════════════════════════╩═══════════════════════════════════════╩═══════════════╝
Там есть фундаментальные проблемы с этим, если у вас есть какие-либо динамический SQL - что потенциально может обратиться к любому объекту на всех, особенно в сочетании с INFORMATION_SCHEMA. Справедливо ли считать, что использование динамического SQL достаточно редко, что это не проблема? –
Я был бы очень рад, если бы нашел те, которые, как известно, отсутствуют. Динамический SQL - это тема, с которой я сейчас не готов разбираться. –