Database
 sql >> база данни >  >> RDS >> Database

Поглед към DBCC CHECKCONSTRAINTS и I/O

Често срещан елемент, използван при проектирането на база данни, е ограничението. Ограниченията се предлагат в различни варианти (например по подразбиране, уникални) и налагат целостта на колоната(ите), в която съществуват. Когато се прилагат добре, ограниченията са мощен компонент в дизайна на база данни, тъй като пречат на данни, които не отговарят на зададените критерии, да попаднат в база данни. Въпреки това, ограниченията могат да бъдат нарушени с помощта на команди като WITH NOCHECK и IGNORE_CONSTRAINTS . Освен това, когато използвате REPAIR_ALLOW_DATA_LOSS опция с произволен DBCC CHECK команда за поправяне на повреда в базата данни, ограниченията не се вземат предвид.

Следователно е възможно да има невалидни данни в базата данни - или данни, които не се придържат към ограничение, или данни, които вече не поддържат очакваната връзка между първичен и външен ключ. SQL Server включва DBCC CHECKCONSTRAINTS изявление за намиране на данни, които нарушават ограниченията. След като се изпълни която и да е опция за ремонт, изпълнете DBCC CHECKCONSTRAINTS за цялата база данни, за да се гарантира, че няма проблеми и може да има моменти, когато е подходящо да се изпълни CHECKCONSTRAINTS за ограничение за избор или таблица. Поддържането на целостта на данните е от решаващо значение и макар че не е типично да се изпълняват DBCC CHECKCONSTRAINTS на планирана база, за да намерите невалидни данни, когато трябва да ги стартирате, добре е да разберете въздействието върху производителността, което може да създаде.

DBCC CHECKCONSTRAINTS може да се изпълни за едно ограничение, таблица или цялата база данни. Подобно на други команди за проверка, това може да отнеме значително време за завършване и ще изразходва системни ресурси, особено за по-големи бази данни. За разлика от други команди за проверка, CHECKCONSTRAINTS не използва моментна снимка на базата данни.

С разширени събития можем да изследваме използването на ресурси, когато изпълняваме DBCC CHECKCONSTRAINTS за масата. За да покажа по-добре въздействието, стартирах скрипта Create Enlarged AdventureWorks Tables.sql от Jonathan Kehayias (блог | @SQLPoolBoy), за да създам по-големи таблици. Скриптът на Джонатан създава само индексите за таблиците, така че изявленията по-долу са необходими за добавяне на няколко избрани ограничения:

USE [AdventureWorks2012];
GO
 
ALTER TABLE [Sales].[SalesOrderDetailEnlarged]
WITH CHECK ADD CONSTRAINT [FK_SalesOrderDetailEnlarged_SalesOrderHeaderEnlarged_SalesOrderID]
FOREIGN KEY([SalesOrderID])
REFERENCES [Sales].[SalesOrderHeaderEnlarged] ([SalesOrderID])
ON DELETE CASCADE;
GO
 
ALTER TABLE [Sales].[SalesOrderDetailEnlarged]
WITH CHECK ADD CONSTRAINT [CK_SalesOrderDetailEnlarged_OrderQty]
CHECK (([OrderQty]>(0)))
GO
 
ALTER TABLE [Sales].[SalesOrderDetailEnlarged]
WITH CHECK ADD CONSTRAINT [CK_SalesOrderDetailEnlarged_UnitPrice]
CHECK (([UnitPrice]>=(0.00)));
GO
 
ALTER TABLE [Sales].[SalesOrderHeaderEnlarged]
WITH CHECK ADD CONSTRAINT [CK_SalesOrderHeaderEnlarged_DueDate]
CHECK (([DueDate]>=[OrderDate]))
GO
 
ALTER TABLE [Sales].[SalesOrderHeaderEnlarged]
WITH CHECK ADD CONSTRAINT [CK_SalesOrderHeaderEnlarged_Freight]
CHECK (([Freight]>=(0.00)))
GO

Можем да проверим какви ограничения съществуват с помощта на sp_helpconstraint :

EXEC sp_helpconstraint '[Sales].[SalesOrderDetailEnlarged]';
GO


sp_helpconstraint изход

След като ограниченията съществуват, можем да сравним използването на ресурсите за DBCC CHECKCONSTRAINTS за едно ограничение, таблица и цялата база данни с помощта на разширени събития. Първо ще създадем сесия, която просто улавя sp_statement_completed събития, включва sql_text действие и изпраща изхода към ring_buffer :

CREATE EVENT SESSION [Constraint_Performance] ON SERVER
ADD EVENT sqlserver.sp_statement_completed
(
  ACTION(sqlserver.database_id,sqlserver.sql_text)
)
ADD TARGET package0.ring_buffer
(
  SET max_events_limit=(5000)
)
WITH 
(
    MAX_MEMORY=32768 KB, EVENT_RETENTION_MODE=ALLOW_SINGLE_EVENT_LOSS,
    MAX_DISPATCH_LATENCY=30 SECONDS, MAX_EVENT_SIZE=0 KB,
    MEMORY_PARTITION_MODE=NONE, TRACK_CAUSALITY=OFF, STARTUP_STATE=OFF
);
GO

След това ще започнем сесията и ще стартираме всеки от DBCC CHECKCONSTRAINT команди, след което изведете буфера на пръстена във временна таблица за манипулиране. Обърнете внимание, че DBCC DROPCLEANBUFFERS изпълнява преди всяка проверка, така че всяка да започва от студен кеш, като запазва поле за тестване на ниво.

ALTER EVENT SESSION [Constraint_Performance]
ON SERVER
STATE=START;
GO
 
USE [AdventureWorks2012];
GO
 
DBCC DROPCLEANBUFFERS;
GO
DBCC CHECKCONSTRAINTS ('[Sales].[CK_SalesOrderDetailEnlarged_OrderQty]') WITH NO_INFOMSGS;
GO
DBCC DROPCLEANBUFFERS;
GO
DBCC CHECKCONSTRAINTS ('[Sales].[FK_SalesOrderDetailEnlarged_SalesOrderHeaderEnlarged_SalesOrderID]') WITH NO_INFOMSGS;
GO
DBCC DROPCLEANBUFFERS;
GO
DBCC CHECKCONSTRAINTS ('[Sales].[SalesOrderDetailEnlarged]') WITH NO_INFOMSGS;
GO
DBCC DROPCLEANBUFFERS;
GO
DBCC CHECKCONSTRAINTS WITH ALL_CONSTRAINTS, NO_INFOMSGS;
GO
 
DECLARE @target_data XML;
 
SELECT @target_data = CAST(target_data AS XML)
  FROM sys.dm_xe_sessions AS s
  INNER JOIN sys.dm_xe_session_targets AS t 
  ON t.event_session_address = s.[address]
  WHERE s.name = N'Constraint_Performance'
  AND t.target_name = N'ring_buffer';
 
SELECT
  n.value('(@name)[1]', 'varchar(50)') AS event_name,
  DATEADD(HOUR ,DATEDIFF(HOUR, SYSUTCDATETIME(), SYSDATETIME()),n.value('(@timestamp)[1]', 'datetime2')) AS [timestamp],
  n.value('(data[@name="duration"]/value)[1]', 'bigint') AS duration,
  n.value('(data[@name="physical_reads"]/value)[1]', 'bigint') AS physical_reads,
  n.value('(data[@name="logical_reads"]/value)[1]', 'bigint') AS logical_reads,
  n.value('(action[@name="sql_text"]/value)[1]', 'varchar(max)') AS sql_text,
  n.value('(data[@name="statement"]/value)[1]', 'varchar(max)') AS [statement]
INTO #EventData
FROM @target_data.nodes('RingBufferTarget/event[@name=''sp_statement_completed'']') AS q(n);
GO
 
ALTER EVENT SESSION [Constraint_Performance]
ON SERVER
STATE=STOP;
GO

Разбор на ring_buffer във временна таблица може да отнеме известно време (около 20 секунди на моята машина), но многократното запитване на данните е по-бързо от временна таблица, отколкото чрез ring_buffer . Ако погледнем изхода, ще видим, че има няколко оператора, изпълнени за всеки DBCC CHECKCONSTRAINTS :

SELECT *
FROM #EventData
WHERE [sql_text] LIKE 'DBCC%';


Изход за разширени събития

Използване на разширени събития за копаене във вътрешната работа на CHECKCONSTRAINTS е интересна задача, но това, което наистина ни интересува, е потреблението на ресурси – по-специално I/O. Можем да обобщим physical_reads за всяка команда за проверка за сравняване на I/O:

SELECT [sql_text], SUM([physical_reads]) AS [Total Reads]
FROM #EventData
WHERE [sql_text] LIKE 'DBCC%'
GROUP BY [sql_text];


Агрегиран I/O за проверки

За да провери ограничение, SQL Server трябва да прочете данните, за да намери редове, които могат да нарушат ограничението. Дефиницията на CK_SalesOrderDetailEnlarged_OrderQty ограничението е [OrderQty] > 0 . Ограничението на външния ключ, FK_SalesOrderDetailEnlarged_SalesOrderHeaderEnlarged_SalesOrderID , установява връзка на SalesOrderID между [Sales].[SalesOrderHeaderEnlarged] и [Sales].[SalesOrderDetailEnlarged] маси. Интуитивно може да изглежда, че проверката на ограничението на външния ключ ще изисква повече I/O, тъй като SQL Server трябва да чете данни от две таблици. Въпреки това, [SalesOrderID] съществува в крайното ниво на IX_SalesOrderHeaderEnlarged_SalesPersonID неклъстериран индекс в [Sales].[SalesOrderHeaderEnlarged] таблица и в IX_SalesOrderDetailEnlarged_ProductID индекс на [Sales].[SalesOrderDetailEnlarged] маса. Като такъв, SQL Server сканира тези два индекса, за да сравни [SalesOrderID] стойности между двете таблици. Това изисква малко над 19 000 четения. В случай на CK_SalesOrderDetailEnlarged_OrderQty ограничение, [OrderQty] колоната не е включена в нито един индекс, така че се извършва пълно сканиране на клъстерирания индекс, което изисква над 72 000 четения.

Когато всички ограничения за дадена таблица са проверени, изискванията за I/O са по-високи, отколкото ако е проверено едно ограничение, и те се увеличават отново, когато се провери цялата база данни. В примера по-горе, [Sales].[SalesOrderHeaderEnlarged] и [Sales].[SalesOrderDetailEnlarged] таблиците са непропорционално по-големи от другите таблици в базата данни. Това не е необичайно в реалните сценарии; много често базите данни имат няколко големи таблици, които съставляват голяма част от базата данни. Когато изпълнявате CHECKCONSTRAINTS за тези таблици, имайте предвид потенциалната консумация на ресурси, необходима за проверката. Извършвайте проверки в неработно време, когато е възможно, за да сведете до минимум въздействието на потребителите. В случай, че проверките трябва да се изпълняват през нормалното работно време, разбирането какви ограничения съществуват и какви индекси съществуват, за да поддържат валидирането, може да помогне да се прецени ефектът от проверката. Можете първо да изпълните проверки в среда за тестване или разработка, за да разберете въздействието върху производителността, но след това може да съществуват вариации въз основа на хардуер, сравними данни и т.н.  И накрая, не забравяйте, че всеки път, когато изпълнявате команда за проверка, която включва REPAIR_ALLOW_DATA_LOSS опция, следвайте поправката с DBCC CHECKCONSTRAINTS . Поправката на база данни не взема предвид никакви ограничения, тъй като повредата е фиксирана, така че освен потенциална загуба на данни, може да се окажете с данни, които нарушават едно или повече ограничения във вашата база данни.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Проследяване на сигнали с модел на данни за обработка на сигнали

  2. Как да коригирам ORA-12505, TNS:слушателят в момента не знае за SID, даден в дескриптора на свързване

  3. Използване на модулни зависимости, част 2

  4. Какво бих искал да видя в Amazon EC2 за управление на бази данни

  5. Програмиране на база данни на Python със SQL Express за начинаещи