На уровне метаданных, в SQL Server существуют понятия soft и hard зависимостей. Последние всегда валидируют связанные объекты при их изменении или попытке удаления.
Пример таких зависимостей – скалярная функция, которая используется в COMPUTED столбце:
CREATE FUNCTION dbo.udf_Computed (@a INT)
RETURNS INT
AS BEGIN
RETURN @a
END
GO
CREATE TABLE dbo.tbl_Table (
ID INT,
Value AS dbo.udf_Computed(ID)
)
GO
DROP FUNCTION dbo.udf_Computed
GO
Msg 3729, Level 16, State 1, Line 2
Cannot DROP FUNCTION 'dbo.udf_Computed' because it is being referenced by object 'tbl_Table'.
В свою очередь, soft зависимости таким свойством не обладают. На практике же, существует большое количество нюансов с которыми я столкнулся, когда реализовывал поиск зависимостей в этом туле. Если будет желание могу описать такие случаи в отдельном посте по мере появления свободного времени.
Спасибо за статью. Хотел бы обратить Ваше внимание на несколько нюансов (insertRandomData).
Системное представление sys.all_objects содержит в себе и пользовательские и системные объекты. А поскольку фильтром Вы оставляете только пользовательские таблицы (type = 'U'), то целесообразно делать выборку из sys.objects. За счет этого Вы получите более эффективный план выполнения.
Также меня немного настораживает соединение с systypes. Возможно Вы хотели сделать соединение по user_type_id. В противном случае, возможна ситуация когда можно получить дублирование строк.
В общем, мой вариант Вашего запроса:
SELECT c.column_id
, c.name
, TYPE_NAME(c.user_type_id)
, c.max_length
FROM sys.objects o
JOIN sys.columns c ON c.[object_id] = o.[object_id]
WHERE o.[type] = 'U'
AND TYPE_NAME(c.system_type_id) != 'sysname'
AND o.name LIKE @childTableName
ORDER BY c.column_id;
Замечание верное. Так изначально и планировалось, но как-то не срослось, потому что перед вставкой нового профиля делается проверка — существует ли уже такой профиль в таблице. Делать это по хешу оказалось быстрее.
Тут скорее важен не размер базы, а размер отдельных таблиц. которые имеют большой размер и неприятную особенность — в них часто изменяются данные. Именно для таких таблиц — целесообразно делать дефрагментацию индексов.
Небольшое замечание — при пересоздании таблицы, впрочем, как и любого другого объекта — меняется его object_id.
Попробуйте несколько раз выполнить этот скрипт, чтобы увидеть описанную ситуацию:
IF OBJECT_ID('dbo.test1', 'U') IS NOT NULL
DROP TABLE dbo.test1
GO
CREATE TABLE dbo.test1
(
ID INT,
CONSTRAINT PK_test1_ID PRIMARY KEY (ID)
)
GO
SELECT OBJECT_ID('dbo.test1')
Поэтому, во избежание коллизий, желательно привязываться не к object_id, а к полному имени объекта (схема + имя).
Пример таких зависимостей – скалярная функция, которая используется в COMPUTED столбце:
В свою очередь, soft зависимости таким свойством не обладают. На практике же, существует большое количество нюансов с которыми я столкнулся, когда реализовывал поиск зависимостей в этом туле. Если будет желание могу описать такие случаи в отдельном посте по мере появления свободного времени.
Системное представление sys.all_objects содержит в себе и пользовательские и системные объекты. А поскольку фильтром Вы оставляете только пользовательские таблицы (type = 'U'), то целесообразно делать выборку из sys.objects. За счет этого Вы получите более эффективный план выполнения.
Также меня немного настораживает соединение с systypes. Возможно Вы хотели сделать соединение по user_type_id. В противном случае, возможна ситуация когда можно получить дублирование строк.
В общем, мой вариант Вашего запроса:
В такой ситуации мы вообще не сможем изменить никаких индексов:
Msg 50000, Level 16, State 1, Procedure ddl_Server, Line 7 Error
Попробуйте несколько раз выполнить этот скрипт, чтобы увидеть описанную ситуацию:
Поэтому, во избежание коллизий, желательно привязываться не к object_id, а к полному имени объекта (схема + имя).
Спасибо за замечание. Немного поправил скрипт. Для Вашего примера мы получаем следующий скрипт:
PS. Генерацию остальных индексов планирую добавить в продолжении.