В предыдущей лекции рассказывалось об использовании транзакций для обеспечения целостности данных. В этой лекции мы поговорим об обеспечении целостности данных путем отслеживания изменений и сохранения архивных версий данных, которые могут при необходимости восстанавливаться без восстановления всей базы данных.
Архивные данные могут принимать различные формы, от данных аудита до хранилищ данных для аналитиков. В этой лекции речь, главным образом, пойдет о методах аудита и архивации данных. Одна из главных целей этой лекции - продемонстрировать способы восстановления данных и отслеживания изменений. Как видно из приведенного выше списка задач, существует несколько способов достижения этой цели. Однако Microsoft SQL Server 2005 имеет и другие методы, которые будут выделяться на протяжении всей лекции как альтернативные. В процессе чтения просматривайте Советы, которые помогут узнать об этих альтернативных методах.
В SQL Server 2005 существует возможность создать моментальный снимок данных. Моментальный снимок базы данных - это, по сути, указатель места момента времени, в который он создается. В любой момент времени после этого вы можете вернуться к снимку и удалить изменения, которые были внесены в данные. Ниже приводится краткий список ситуаций, в которых моментальные снимки могут оказаться очень полезными.
Мы видим, что моментальные снимки базы данных могут быть очень полезными в разработке, тестировании и производственной среде.
Моментальные снимки базы данных можно создать только при помощи Transact-SQL. Через интерфейс SQL Server Management Studio создать их нельзя. Ниже приводится код для создания моментального снимка базы данных Adventure Works (этот код можно найти в файлах примеров под именем Create Snapshot.sql ).
Adventure Works, введите и выполните следующий код. Внесите исправления в путь к файлу, чтобы он соответствовал вашей структуре папок.CREATE DATABASE AdventureWorks_SBSExample1 ON
( NAME = AdventureWorks_Data,
FILENAME =
"C:\MySnapshotData\AdventureWorks_SBSExample1.snapshot" )
AS SNAPSHOT OF AdventureWorks;
GO
Первое, что следует отметить – это то, что инструкция CREATE представляет собой ту же инструкцию, которая используется для создания базы данных. Это значит, что пользователь, который выполняет инструкцию, должен иметь необходимые разрешения на создание баз данных на сервере, с которым он работает. Далее следует отметить, что моментальный снимок должен отражать все файлы, которые содержатся в исходной базе данных. В данном случае, база Adventure Works имеет только один файл – Adventure Works_Data. Но если в исходной базе данных используется более одного файла или группы файлов, вам придется добавить предложение NAME и FILENAME для каждого файла.
Последний фрагмент кода уведомляет SQL Server о том, что нужно создать моментальный снимок определенной базы данных. Не забывайте, что моментальные снимки и исходные базы данных должны размещаться на одном сервере.
Имена моментальных снимков
При назначении имени моментального снимка следует выбирать понятные имена. В нашем примере SBSExample1 –это производное от названия книги, Step-by-Step. Однако, возможно, вам покажется более удобным использовать в имени дату и время создания снимка, чтобы пользователи могли легко понять, какие данные в нем содержатся.
Имена файлов
Обычно удобно создать имя файла, исходя из имени базы данных или логического имени файла. Более того, расширение имени файла тоже может что-то означать. В Электронной документации SQL Server 2005 используется расширение .ss, а в нашем примере - расширение .snapshot. Используйте то соглашение о назначении имен, которое вам лучше подходит.
Использование дискового пространства
Необходимо учитывать размер дискового пространства, необходимого для моментального снимка. Моментальные снимки содержат только изменения исходной базы данных на момент создания снимка. Это значит, что чем больше изменений было сделано в исходной базе данных, тем больше пространства потребуется для хранения моментальных снимков с записью этих изменений. Учтите также и то, сколько снимков нужно хранить.
Как и в случае создания моментальных снимков, чтобы вернуться к моментальному снимку базы данных, придется использовать T-SQL. Для возврата к снимку базы данных в T-SQL используется команда RESTORE DATABASE.

RESTORE DATABASE, для возврата к выбранному моментальному снимку (этот код можно найти в файлах примеров под именем FromSnapshot.sql ).RESTORE DATABASE AdventureWorks FROM DATABASE_SNAPSHOT = "AdventureWorks_SBSExample1"
В отличие от создания и возврата к моментальному снимку, удалить моментальный снимок можно и через T-SQL, и через интерфейс SQL Server Management Studio. Как вы уже успели заметить, для выполнения операций моментальные снимки используют варианты команды базы данных в T-SQL. То же происходит и при удалении моментального снимка.
При удалении моментального снимка с помощью T-SQL используйте команду DROP DATABASE. Для удаления моментальных снимков существуют те же ограничения, что и для удаления баз данных. Перед выполнением действия необходимо закрыть все соединения и иметь разрешение на удаление базы данных. Чтобы удалить созданный нами моментальный снимок, введите и выполните следующий код в окне нового запроса. (Этот код можно найти в файлах примеров под именем DeleteSnapshot.sql.)
DROP DATABASE AdventureWorks_SBSExample1;
В SQL Server Management Studio можно удалить снимок базы данных так же, как и обычную базу данных.

KILL всем соединениям базы данных.При использовании моментального снимка базы данных имеют место следующие влияния на исходную базу данных:
Перемещая данные в таблицы хроники, можно освободить систему транзакций от всплесков, имеющих место в том случае, когда к ней выполняются запросы для создания отчетов. Таблицы хроники могут быть оптимизированы для запросов и обслуживаться отдельно от всей остальной системы. Существует несколько способов создания таких таблиц и поддержания их в актуальном состоянии. Мы рассмотрим несколько примеров, которые используют для загрузки таблиц и T-SQL, и службу агент SQL Server.
Затем мы создадим итоговую таблицу из базы данных Adventure Works, которая будет отслеживать продажи данного продукта с сортировкой по продавцам. Задача - выполнив запрос по фамилии продавца, быстро узнать, сколько единиц данного изделия он продал.
USE AdventureWorks;
GO
CREATE TABLE Sales.SalesPersonProductWeeklySummary
(SalesPersonID INT
,SalesPersonFirstName NVARCHAR(50)
,SalesPersonLastName NVARCHAR(50)
,OrderWeekOfYear INT
,OrderYear INT ,ProductID INT
,ProductName NVARCHAR(50)
,WeeklyOrderQty INT
,WeeklyLineTotal MONEY );
GO
CREATE CLUSTERED INDEX cidx_SalesPersonProductWeeklySummary
ON Sales.SalesPersonProductWeeklySummary(OrderYear,
OrderWeekOfYear, SalesPersonID);
GO
SalesPersonProductWeeklySummary данных. Следующий код (он включен в файлы примеров под именем CreateUspGetWeeklySalesSummary.sql ) создает процедуру. Введите и выполните код в окне нового запроса.USE AdventureWorks GO
CREATE PROCEDURE Sales.uspGetSalesWeeklySummary
(@StartOfWeek DATETIME
,@EndOfWeek DATETIME )
AS
BEGIN
SELECT hdr.SalesPersonID
,cntc.FirstName AS SalesPersonFirstName
,cntc.LastName AS SalesPersonLastName
,DATEPART(WEEK, hdr.OrderDate) AS OrderWeekOfYear
,DATEPART(YEAR, hdr.OrderDate) AS OrderYear
,prod.ProductID ,prod.Name AS ProductName
,SUM(dtl.OrderQty) as WeeklyOrderQty
,SUM(dtl.LineTotal) as WeeklyLineTotal
FROM Sales.SalesOrderHeader hdr
INNER JOIN Sales.SalesOrderDetail dtl
ON hdr.SalesOrderID = dtl.SalesOrderID
INNER JOIN HumanResources.Employee emp
ON hdr.SalesPersonID = emp.EmployeeID
INNER JOIN Person.Contact cntc
ON emp.ContactID = cntc.ContactID
INNER JOIN Production.Product prod
ON dtl.ProductID = prod.ProductID
WHERE hdr.OrderDate BETWEEN @StartOfWeek AND @EndOfWeek
GROUP BY hdr.SalesPersonID
,cntc.FirstName
,cntc.LastName
,prod.ProductID
,prod.Name
,hdr.OrderDate
END;
GO
Sales можно гарантировать, что разрешения на доступ к сведениям о продажах будут применяться и к новым объектам сводных данных.uspGetWeeklySalesSummary, выполнив следующий код (его можно найти в файле примеров с именем LoadSalesPersonProduct WeeklySummary.sql ). Введите и выполните код в окне нового запроса.INSERT INTO Sales.SalesPersonProductWeeklySummary
(SalesPersonID
,SalesPersonFirstName
,SalesPersonLastName
,OrderWeekOfYear
,OrderYear
,ProductID
,ProductName
,WeeklyOrderQty
,WeeklyLineTotal
)
EXEC Sales.uspGetSalesWeeklySummary
@StartOfWeek = "1/1/2004 00:00:00",
@EndOfWeek = "1/7/2004 11:59:59";
GO
Если вам приходится выполнять больше одной операции загрузки, то это может быть наилучшим вариантом.

Adventure Works.ScheduledJobStep.sql.)DECLARE @StartOfWeek datetime
,@EndOfWeek datetime
SET @StartOfWeek = CAST(ROUND(CAST(DATEADD(DAY, -2, GETDATE())
AS FLOAT),0,1) AS DATETIME)
SET @EndOfWeek = DATEADD(DAY, 7, @StartOfWeek)
INSERT INTO Sales.SalesPersonProductWeeklySummary
(SalesPersonID
,SalesPersonFirstName
,SalesPersonLastName
,OrderWeekOfYear
,OrderYear
,ProductID
,ProductName
,WeeklyOrderQty
,WeeklyLineTotal
)
EXEC Sales.uspGetSalesWeeklySummary
@StartOfWeek,
@EndOfWeek
DateTime. Это можно сделать следующим образом: SET @StartOfWeek = CAST(CONVERT(VARCHAR, DATEADD(DAY, -2, GETDATE()), 101) AS DATETIME).Можете попробовать сделать это по-другому. Один метод использует конверсию строк, в то время как другой код использует конверсию чисел и может выполняться быстрее.

Еще одна возможность сохранить итоговые данные– это использование индексированных представлений. Индексированные представления также называют материализованными представлениями, потому что они вычисляют и хранят данные. От обычных представлений их отличает наличие уникальных
Далее мы создадим индексированное представление, которое будет возвращать продажи отдельных изделий в 2004 году, сгруппированные по продавцам. Индексированные представления имеют много ограничений, которые препятствуют их созданию на основе изменяющихся значений. В этом случае мы используем диапазон данных, в котором данные, вероятнее всего, не будут изменяться. Если вам нужно показать эти данные по месяцам, то придется создать отдельное индексированное представление для каждого месяца.
Create View.sql ) в окне нового запроса в SQL Server Management Studio. Фрагменты кода, выделенные полужирным шрифтом, подробно объясняются на врезке "Параметры, обязательные при работе с индексированными представлениями". Они обязательны для применения индекса.USE AdventureWorks;
GO
IF EXISTS(SELECT 1 FROM sys.objects WHERE name =
N'v_SalesPerson2004ProductSummary')
DROP VIEW Sales.v_SalesPerson2004ProductSummary
GO
SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON
GO
CREATE VIEW Sales.v_SalesPerson2004ProductSummary
WITH SCHEMABINDING
AS
SELECT hdr.SalesPersonID
,cntc.FirstName AS SalesPersonFirstName
,cntc.LastName AS SalesPersonLastName
,prod.ProductID
,prod.Name AS ProductName
,COUNT_BIG(*) AS OrderLineCount
,SUM(dtl.OrderQty) as OrderQty
,SUM(dtl.LineTotal) as LineTotal
FROM Sales.SalesOrderHeader hdr
INNER JOIN Sales.SalesOrderDetail dtl
ON hdr.SalesOrderID = dtl.SalesOrderID
INNER JOIN HumanResources.Employee emp
ON hdr.SalesPersonID = emp.EmployeeID
INNER JOIN Person.Contact cntc
ON emp.ContactID = cntc.ContactID
INNER JOIN Production.Product prod
ON dtl.ProductID = prod.ProductID
WHERE hdr.OrderDate BETWEEN
CONVERT(DATETIME, "1/1/2004 00:00:00",120)
AND CONVERT(DATETIME,"12/31/2004 23:59:59",120)
GROUP BY hdr.SalesPersonID
,cntc.FirstName
,cntc.LastName
,prod.ProductID
,prod.Name;
GO
ProductID. Выполните следующий код (его можно найти среди файлов примеров под именем AddIndex.sql ).USE AdventureWorks
GO
CREATE UNIQUE CLUSTERED INDEX cidx_v_SalesPerson2004ProductSummary
ON Sales.v_SalesPerson2004ProductSummary
(SalesPersonID
,ProductID);
GO
Хотя использование индексированных представлений способно повысить производительность при извлечении итоговых данных из среды, оно связано с некоторыми обязательными параметрами и ограничениями. Представление, созданное в разделе "Создаем индексированное представление для итогов продаж" было разработано для обхода некоторых из таких ограничений.
ANSI_NULLS и QUOTED_IDENTIFIER должны быть установлены на ON. Параметр ANSI_NULLS должен быть включен также и для базовой таблицы, лежащей в основе представления.SCHEMA_BINDING. Оно объединит схему со схемами базовых таблиц.GROUP BY необходимо включить в список SELECT COUNT_BIG(*).GET-DATE(), поскольку она не является детерминированной. Необходимо также конвертировать даты в строковых форматах в даты в детерминированных форматах. В данном примере мы конвертируем строковое выражение в тип данных DATETIME при помощи канонического стандартного стиля ODBC (120).Следует иметь в виду еще несколько параметров и ограничений. Полный список можно найти в Электронной документации по SQL Server 2005 в теме "Создание индексированных представлений". Обязательно ознакомьтесь с этим списком, прежде чем приступать к использованию индексированных представлений, поскольку окончательный проект может оказаться слишком усложненным и не даст желательных преимуществ.
В предыдущих двух разделах мы узнали, как хранить итоговые архивные данные и осуществлять к ним доступ. Теперь мы познакомимся с некоторыми методами отслеживания меняющихся данных в самой таблице и за пределами исходной таблицы. Уровень аудита, который следует выбирать, зависит от того, что в действительности требуется узнать.
Можно выбрать простой уровень аудита, при котором будет записываться только дата изменения, или сложный уровень, при котором будет вестись полная запись изменения с возможностью восстановления, если возникнет необходимость. В последнем варианте используются столбцы аудита, таблицы аудита или их сочетание.
Преимущество аудита с помощью столбцов заключается в том, что контрольная информация размещается в той же таблице, что и данные. В табл. 7.1 перечислены некоторые столбцы аудита, которые обычно добавляются в таблицы.
| Отслеживаемые события | Типы данных | Комментарии |
|---|---|---|
INSERT, UPDATE, или DELETE |
DATETIME |
Используется для отслеживания даты и времени выполнения отслеживаемого действия. |
Обычно используется с функцией GETDATE() как значение по умолчанию, но значение может задаваться и вызывающим приложением. |
||
INSERT, UPDATE или DELETE |
VARCHAR |
Используется для отслеживания имени пользователя или приложения, выполняющего отслеживаемое действие. |
DELETE |
BIT/TINYINT |
Используется для того, чтобы пометить данные как удаляемые. Это может с большой эффективностью применяться в индексировании и фильтрации. |
По этой таблице можно сделать вывод, что изменения данных в действительности не протоколируются. Наиболее эффективный способ использования столбцов аудита – это отслеживание факта внесения изменения, времени изменения и лица или приложения, выполнившего это изменение. Можно использовать эти столбцы в любой комбинации, чтобы отслеживать изменения в записях в
Person.Address базы данных Adventure Works.Person.Address ) и определив события, которые будут отслеживаться, нужно решить, какие столбцы добавить в таблицу.ModifiedDate уже существует в таблице. Он будет отслеживать дату, показывающую, когда запись была в последний раз изменена или удалена.CreatedDate будет отслеживать, когда была создана запись. Тип данных этого столбца DATETIME, с использованием функции GETDATE() для предоставления текущей даты как значения по умолчанию.ModifiedBy —это столбец VARCHAR, который будет содержать имя пользователя или некоторые другие средства для идентификации пользователя или приложения, которые внесли изменения.IsDeleted - столбец с типом данных BIT, который будет использоваться для записи об удалении строки. Дата и пользователь будут отслеживаться через столбцы ModifiedDate и ModifiedBy. Если запись была удалена, этот столбец будет помечен, а в измененном столбце будут сведения о том, кто и когда удалил запись.Person.Address (этот код можно найти в файлах примеров под именем AlterTable.sql ).USE AdventureWorks
GO
ALTER TABLE Person.Address
ADD CreatedDate DATETIME NULL DEFAULT GETDATE()
,ModifiedBy VARCHAR(50) NULL
,IsDeleted BIT DEFAULT (0)
CreatedDate значение, показывающее, что столбец был создан до того, как был начат аудит. Чтобы задать значение CreatedDate, выполните следующий код:UPDATE Person.Address SET CreatedDate = "1/1/1980";
WHERE IsDeleted = 0
Теперь мы знаем, как использовать аудит для уведомления о сделанных изменениях. Однако единственное изменение, которое может быть легко отменено - это событие DELETE. Достаточно просто сбросить флаг IsDeleted, и данные будут снова доступны. Существует также возможность отменить событие CREATE, если об этом действии имеется достаточная информация. Однако если нужно иметь возможность полностью отслеживать состояние данных перед изменением, возможно, лучшим вариантом окажется использование таблиц аудита. Эту возможность следует использовать с осторожностью, потому что она может вызвать много проблем с обслуживанием и производительностью. Такие проблемы возникают потому, что приходится копировать данные в таблицу аудита и изменять их в исходной таблице. Для этого примера мы зададим аудит на базе таблицы в таблице Sales.Special . Цель – отслеживание любых изменений в этой таблице и обеспечение возможности отменить изменения после того, как они были зафи
ксированы.
Adventure Works таблицу Sales.SpecialOffer.Sales.SpecialOffer и выбрав из контекстного меню команды Script Table As, Create To, New Query Editor Window (Создать сценарий для таблицы, Используя CREATE, В новом окне редактора запросов). После этого откроется новое окно запроса с готовым для редактирования сценарием CREATE TABLE.CREATE.Sales.SpecialOffer на Sales.SpecialOffer_Audit.NULL. Благодаря этому таблица будет больше похожа на журнальную таблицу. В этом случае таблица аудита не должна мешать обычным операциям в таблице с самого начала. Это также должно упростить управление таблицей.| Имя столбца | Тип данных |
|---|---|
AuditModifiedDate |
DATETIME |
AuditType |
NVARCHAR(20) |
AdventureWorks. (Этот код можно найти в файлах примеров под именем CreateAuditTable.sql.)USE AdventureWorks;
GO
CREATE TABLE Sales.SpecialOffer_Audit(
SpecialOfferID INT NULL,
Description NVARCHAR(255) NULL,
DiscountPct SMALLMONEY NULL,
[Type] NVARCHAR(50) NULL,
Category NVARCHAR(50) NULL,
StartDate DATETIME NULL,
EndDate DATETIME NULL,
MinQty INT NULL,
MaxQty INT NULL,
rowguid UNIQUEIDENTIFIER NULL,
ModifiedDate DATETIME NULL,
AuditModifiedDate DATETIME NULL,
AuditType NVARCHAR(20) null
);
GO
Основные способы перемещения данных в таблицы аудита в SQL Server 2005 - это триггеры базы данных и новое предложение T-SQL OUTPUT. Однако новое предложение OUTPUT добавляет некоторые интересные возможности. В следующем разделе мы на примере изучим каждый из этих двух вариантов.
Sales.SpecialOffer триггер, который будет записывать предыдущее состояние данных в созданную нами таблицу Sales.SpecialOffer_Audit. Код, приведенный ниже – это пример синтаксической конструкции, которую можно использовать. (Этот код можно найти в файлах примеров под именем CreateTrigger.sql.) Введите и выполните код в окне нового запроса SQL Server Management Studio.USE AdventureWorks
GO
CREATE TRIGGER SpecialOfferUpdateAudit ON Sales.SpecialOffer
FOR UPDATE
AS
INSERT INTO Sales.SpecialOffer_Audit
(SpecialOfferID
,Description
,DiscountPct
,[Type]
,Category
,StartDate
,EndDate
,MinQty
,MaxQty
,rowguid
,ModifiedDate
,AuditModifiedDate
,AuditType)
SELECT TOP 1 d.SpecialOfferID
,d.Description
,d.DiscountPct
,d.[Type]
,d.Category
,d.StartDate
,d.EndDate
,d.MinQty
,d.MaxQty
,d.rowguid
,d.ModifiedDate
,GETDATE()
,'UPDATE'
FROM deleted d; GO
Sales.SpecialOffer, скорее всего, вам придется удалить триггер, который уже существует в таблице ( uSpecial Offer ). Необходимо сохранить сценарий для триггера, чтобы можно было использовать его в дальнейшем. Если этот триггер не удалить, то вы будете получать строки данных в таблице Sales.SpecialOffer_Audit при любом обновлении таблицы.Преимущество использования триггера заключается в том, что он будет захватывать любые обновления, которые произойдут в таблице, независимо от их источника. Это вариант аудита с полным охватом. Если речь идет о данных, которые изменяются без контроля с вашей стороны, то это превосходный вариант. Но если вы тщательно контролируете данные, которые заносятся в таблицу, особенно если это выполняется при помощи хранимых процедур, то в SQL Server 2005 есть новая возможность аудита изменений - предложение OUTPUT.
OUTPUT, каждое событие, которое нужно отслеживать, потребует разработки хранимых процедур и инструкций SQL, которые будут использоваться для обновления ( UPDATE ), вставки ( INSERT ) или удаления ( DELETE ) данных в отслеживаемых таблицах. Предложение OUTPUT предоставляет доступ к вставляемым и удаляемым таблицам в этих процедурах и инструкциях SQL. Теперь не обязательно использовать триггеры для доступа к данным. Представленный ниже код показывает пример использования предложения OUTPUT для аудита обновления в таблице SpecialOffer в таблице SpecialOffer_Audit. (Этот код можно найти в файлах примеров под именем UsingOutputClause.sql.) Введите и выполните данный код в окне нового запроса SQL Server Management Studio.OUTPUT должно вставлять свои данные в табличную переменную, во временную таблицу или - как в данном случае - в постоянную таблицу.USE AdventureWorks
GO
UPDATE Sales.SpecialOffer
SET description = "Big Mountain Tire Sale"
OUTPUT deleted.SpecialOfferID
,deleted.Description
,deleted.DiscountPct
,deleted.[Type]
,deleted.Category
,deleted.StartDate
,deleted.EndDate
,deleted.MinQty
,deleted.MaxQty
,deleted.rowguid
,deleted.ModifiedDate
,GETDATE()
,'UPDATE' INTO Sales.SpecialOffer_Audit
WHERE SpecialOfferID = 10
OUTPUT помещает измененные данные в рамках простого доступа в процессе изменения данных. В процессе операций UPDATE и DELETE доступен префикс DELETED. В процессе операций UPDATE и INSERT доступен префикс INSERTED. Обратите внимание на то, что оба префикса не могут быть доступными одновременно, в отличие от таблиц deleted и inserted, которые используются в триггерах. Эта взаимоисключающая доступность требует, чтобы различные операции обрабатывались по-разному для сбора нужных данных и помещения их в таблицы аудита.OUTPUT можно также использовать для возвращения значения из столбца IDENTITY в процессе операции INSERT.Теперь, когда у нас есть два варианта загрузки данных в таблицу аудита, можно подумать, для чего использовать эти данные. Поскольку все изменения в таблице сохраняются в таблице аудита, можно восстановить любые изменения данных, перезаписав текущие данные изменением, которое нужно сохранить. Таблица аудита может хранить несколько версий данных, поэтому чаще всего это придется делать вручную. Однако можно также создать обслуживающую хранимую процедуру для отмены самого последнего изменения.
UPDATE для перезаписи текущих данных изменением, которое следует восстановить в этой таблице. В данном примере придется использовать либо свойство rowguid, либо столбец SpecialOfferID в сочетании с AuditModifiedDate в качестве критерия для инструкции UPDATE, как показано ниже. (Этот код можно найти в файлах примеров под именем RecoveringChangedData.sql.) Введите и выполните этот код в окне нового запроса SQL Server Management Studio.— В этом сценарии нужно заменить AuditModifiedDate на
—AuditModifiedDate из таблицы SpecialOffer_Audit
USE AdventureWorks
GO
UPDATE Sales.SpecialOffer
SET Description = a.Description
,DiscountPct = a.DiscountPct
,Type = a.Type
,Category = a.Category
,StartDate = a.StartDate
,EndDate = a.EndDate
,MinQty = a.MinQty
,MaxQty = a.MaxQty
,rowguid = a.rowguid
,ModifiedDate = a.ModifiedDate
FROM Sales.SpecialOffer_Audit a
WHERE SpecialOffer.SpecialOfferID = 10
AND a.SpecialOfferID = 10
AND a.AuditModifiedDate = "2006-04-02 22:40:27.513"
Если у вас есть данные, которые нуждаются в регулярном восстановлении, можно инкапсулировать приведенный выше код в хранимую процедуру обслуживания. Однако если вы решите реализовать ее, у вас могут возникнуть проблемы с вводом восстановленных данных. Описанные варианты хорошо подходят для ограниченного количества строк в одной таблице. Если вы работаете с массовой высокопроизводительной загрузкой в нескольких таблицах, следует использовать моментальные снимки, о которых шла речь в первом разделе данной лекции.
Вы научились создавать моментальные снимки данных. Моментальные снимки могут эффективно использоваться для решения различных задач в процессе разработки, тестирования и производства. Можно использовать архивные данные для подведения итогов и анализа данных на определенных отрезках времени. Вы также научились выполнять аудит изменений данных и восстанавливать отдельные записи при помощи данных аудита. Сохраняя архивные данные и отслеживая изменения в базе данных, можно обеспечить целостность данных, используя возможность отмены отдельных изменений, не восстанавливая всю базу данных.
| Чтобы | Выполните следующие действия |
|---|---|
| Создать моментальный снимок базы данных | Воспользуйтесь инструкцией CREATE DATABASE с параметром AS SNAPSHOT OF. |
| Вернуться к моментальному снимку базы данных | Воспользуйтесь инструкцией RESTORE DATABASE с параметром FROM SNAPSHOT. |
| Удалить моментальный снимок базы данных | Воспользуйтесь инструкцией DROP DATABASE или удалите моментальный снимок базы данных через интерфейс SQL Server Management Studio. |
| Запланировать загрузку архивных данных | Создайте новое задание в агенте SQL Server и составьте расписание которое будет удовлетворять вашим потребностям. |
| Вывести итоговую информацию за определенный отрезок времени | Создайте индексированное представление для вывода итогов по одному или нескольким временным отрезкам. |
| Вести аудит изменений данных | Добавьте в таблицу столбцы аудита, в которых будет отслеживаться, кто и когда внес изменение. |
| Отслеживать все изменения данных и иметь возможность восстановить данные после ошибки ввода | Создайте и загрузите таблицу аудита либо при помощи триггеров, либо при помощи предложения OUTPUT. |
В предыдущей лекции рассказывалось об использовании транзакций для обеспечения целостности данных. В этой лекции мы поговорим об обеспечении целостности данных путем отслеживания изменений и сохранения архивных версий данных, которые могут при необходимости восстанавливаться без восстановления всей базы данных.
Архивные данные могут принимать различные формы, от данных аудита до хранилищ данных для аналитиков. В этой лекции речь, главным образом, пойдет о методах аудита и архивации данных. Одна из главных целей этой лекции - продемонстрировать способы восстановления данных и отслеживания изменений. Как видно из приведенного выше списка задач, существует несколько способов достижения этой цели. Однако Microsoft SQL Server 2005 имеет и другие методы, которые будут выделяться на протяжении всей лекции как альтернативные. В процессе чтения просматривайте Советы, которые помогут узнать об этих альтернативных методах.
В SQL Server 2005 существует возможность создать моментальный снимок данных. Моментальный снимок базы данных - это, по сути, указатель места момента времени, в который он создается. В любой момент времени после этого вы можете вернуться к снимку и удалить изменения, которые были внесены в данные. Ниже приводится краткий список ситуаций, в которых моментальные снимки могут оказаться очень полезными.
Мы видим, что моментальные снимки базы данных могут быть очень полезными в разработке, тестировании и производственной среде.
Моментальные снимки базы данных можно создать только при помощи Transact-SQL. Через интерфейс SQL Server Management Studio создать их нельзя. Ниже приводится код для создания моментального снимка базы данных Adventure Works (этот код можно найти в файлах примеров под именем Create Snapshot.sql ).
Adventure Works, введите и выполните следующий код. Внесите исправления в путь к файлу, чтобы он соответствовал вашей структуре папок.CREATE DATABASE AdventureWorks_SBSExample1 ON
( NAME = AdventureWorks_Data,
FILENAME =
"C:\MySnapshotData\AdventureWorks_SBSExample1.snapshot" )
AS SNAPSHOT OF AdventureWorks;
GO
Первое, что следует отметить – это то, что инструкция CREATE представляет собой ту же инструкцию, которая используется для создания базы данных. Это значит, что пользователь, который выполняет инструкцию, должен иметь необходимые разрешения на создание баз данных на сервере, с которым он работает. Далее следует отметить, что моментальный снимок должен отражать все файлы, которые содержатся в исходной базе данных. В данном случае, база Adventure Works имеет только один файл – Adventure Works_Data. Но если в исходной базе данных используется более одного файла или группы файлов, вам придется добавить предложение NAME и FILENAME для каждого файла.
Последний фрагмент кода уведомляет SQL Server о том, что нужно создать моментальный снимок определенной базы данных. Не забывайте, что моментальные снимки и исходные базы данных должны размещаться на одном сервере.
Имена моментальных снимков
При назначении имени моментального снимка следует выбирать понятные имена. В нашем примере SBSExample1 –это производное от названия книги, Step-by-Step. Однако, возможно, вам покажется более удобным использовать в имени дату и время создания снимка, чтобы пользователи могли легко понять, какие данные в нем содержатся.
Имена файлов
Обычно удобно создать имя файла, исходя из имени базы данных или логического имени файла. Более того, расширение имени файла тоже может что-то означать. В Электронной документации SQL Server 2005 используется расширение .ss, а в нашем примере - расширение .snapshot. Используйте то соглашение о назначении имен, которое вам лучше подходит.
Использование дискового пространства
Необходимо учитывать размер дискового пространства, необходимого для моментального снимка. Моментальные снимки содержат только изменения исходной базы данных на момент создания снимка. Это значит, что чем больше изменений было сделано в исходной базе данных, тем больше пространства потребуется для хранения моментальных снимков с записью этих изменений. Учтите также и то, сколько снимков нужно хранить.
Как и в случае создания моментальных снимков, чтобы вернуться к моментальному снимку базы данных, придется использовать T-SQL. Для возврата к снимку базы данных в T-SQL используется команда RESTORE DATABASE.

RESTORE DATABASE, для возврата к выбранному моментальному снимку (этот код можно найти в файлах примеров под именем FromSnapshot.sql ).RESTORE DATABASE AdventureWorks FROM DATABASE_SNAPSHOT = "AdventureWorks_SBSExample1"
В отличие от создания и возврата к моментальному снимку, удалить моментальный снимок можно и через T-SQL, и через интерфейс SQL Server Management Studio. Как вы уже успели заметить, для выполнения операций моментальные снимки используют варианты команды базы данных в T-SQL. То же происходит и при удалении моментального снимка.
При удалении моментального снимка с помощью T-SQL используйте команду DROP DATABASE. Для удаления моментальных снимков существуют те же ограничения, что и для удаления баз данных. Перед выполнением действия необходимо закрыть все соединения и иметь разрешение на удаление базы данных. Чтобы удалить созданный нами моментальный снимок, введите и выполните следующий код в окне нового запроса. (Этот код можно найти в файлах примеров под именем DeleteSnapshot.sql.)
DROP DATABASE AdventureWorks_SBSExample1;
В SQL Server Management Studio можно удалить снимок базы данных так же, как и обычную базу данных.

KILL всем соединениям базы данных.При использовании моментального снимка базы данных имеют место следующие влияния на исходную базу данных:
Перемещая данные в таблицы хроники, можно освободить систему транзакций от всплесков, имеющих место в том случае, когда к ней выполняются запросы для создания отчетов. Таблицы хроники могут быть оптимизированы для запросов и обслуживаться отдельно от всей остальной системы. Существует несколько способов создания таких таблиц и поддержания их в актуальном состоянии. Мы рассмотрим несколько примеров, которые используют для загрузки таблиц и T-SQL, и службу агент SQL Server.
Затем мы создадим итоговую таблицу из базы данных Adventure Works, которая будет отслеживать продажи данного продукта с сортировкой по продавцам. Задача - выполнив запрос по фамилии продавца, быстро узнать, сколько единиц данного изделия он продал.
USE AdventureWorks;
GO
CREATE TABLE Sales.SalesPersonProductWeeklySummary
(SalesPersonID INT
,SalesPersonFirstName NVARCHAR(50)
,SalesPersonLastName NVARCHAR(50)
,OrderWeekOfYear INT
,OrderYear INT ,ProductID INT
,ProductName NVARCHAR(50)
,WeeklyOrderQty INT
,WeeklyLineTotal MONEY );
GO
CREATE CLUSTERED INDEX cidx_SalesPersonProductWeeklySummary
ON Sales.SalesPersonProductWeeklySummary(OrderYear,
OrderWeekOfYear, SalesPersonID);
GO
SalesPersonProductWeeklySummary данных. Следующий код (он включен в файлы примеров под именем CreateUspGetWeeklySalesSummary.sql ) создает процедуру. Введите и выполните код в окне нового запроса.USE AdventureWorks GO
CREATE PROCEDURE Sales.uspGetSalesWeeklySummary
(@StartOfWeek DATETIME
,@EndOfWeek DATETIME )
AS
BEGIN
SELECT hdr.SalesPersonID
,cntc.FirstName AS SalesPersonFirstName
,cntc.LastName AS SalesPersonLastName
,DATEPART(WEEK, hdr.OrderDate) AS OrderWeekOfYear
,DATEPART(YEAR, hdr.OrderDate) AS OrderYear
,prod.ProductID ,prod.Name AS ProductName
,SUM(dtl.OrderQty) as WeeklyOrderQty
,SUM(dtl.LineTotal) as WeeklyLineTotal
FROM Sales.SalesOrderHeader hdr
INNER JOIN Sales.SalesOrderDetail dtl
ON hdr.SalesOrderID = dtl.SalesOrderID
INNER JOIN HumanResources.Employee emp
ON hdr.SalesPersonID = emp.EmployeeID
INNER JOIN Person.Contact cntc
ON emp.ContactID = cntc.ContactID
INNER JOIN Production.Product prod
ON dtl.ProductID = prod.ProductID
WHERE hdr.OrderDate BETWEEN @StartOfWeek AND @EndOfWeek
GROUP BY hdr.SalesPersonID
,cntc.FirstName
,cntc.LastName
,prod.ProductID
,prod.Name
,hdr.OrderDate
END;
GO
Sales можно гарантировать, что разрешения на доступ к сведениям о продажах будут применяться и к новым объектам сводных данных.uspGetWeeklySalesSummary, выполнив следующий код (его можно найти в файле примеров с именем LoadSalesPersonProduct WeeklySummary.sql ). Введите и выполните код в окне нового запроса.INSERT INTO Sales.SalesPersonProductWeeklySummary
(SalesPersonID
,SalesPersonFirstName
,SalesPersonLastName
,OrderWeekOfYear
,OrderYear
,ProductID
,ProductName
,WeeklyOrderQty
,WeeklyLineTotal
)
EXEC Sales.uspGetSalesWeeklySummary
@StartOfWeek = "1/1/2004 00:00:00",
@EndOfWeek = "1/7/2004 11:59:59";
GO
Если вам приходится выполнять больше одной операции загрузки, то это может быть наилучшим вариантом.

Adventure Works.ScheduledJobStep.sql.)DECLARE @StartOfWeek datetime
,@EndOfWeek datetime
SET @StartOfWeek = CAST(ROUND(CAST(DATEADD(DAY, -2, GETDATE())
AS FLOAT),0,1) AS DATETIME)
SET @EndOfWeek = DATEADD(DAY, 7, @StartOfWeek)
INSERT INTO Sales.SalesPersonProductWeeklySummary
(SalesPersonID
,SalesPersonFirstName
,SalesPersonLastName
,OrderWeekOfYear
,OrderYear
,ProductID
,ProductName
,WeeklyOrderQty
,WeeklyLineTotal
)
EXEC Sales.uspGetSalesWeeklySummary
@StartOfWeek,
@EndOfWeek
DateTime. Это можно сделать следующим образом: SET @StartOfWeek = CAST(CONVERT(VARCHAR, DATEADD(DAY, -2, GETDATE()), 101) AS DATETIME).Можете попробовать сделать это по-другому. Один метод использует конверсию строк, в то время как другой код использует конверсию чисел и может выполняться быстрее.

Еще одна возможность сохранить итоговые данные– это использование индексированных представлений. Индексированные представления также называют материализованными представлениями, потому что они вычисляют и хранят данные. От обычных представлений их отличает наличие уникальных
Далее мы создадим индексированное представление, которое будет возвращать продажи отдельных изделий в 2004 году, сгруппированные по продавцам. Индексированные представления имеют много ограничений, которые препятствуют их созданию на основе изменяющихся значений. В этом случае мы используем диапазон данных, в котором данные, вероятнее всего, не будут изменяться. Если вам нужно показать эти данные по месяцам, то придется создать отдельное индексированное представление для каждого месяца.
Create View.sql ) в окне нового запроса в SQL Server Management Studio. Фрагменты кода, выделенные полужирным шрифтом, подробно объясняются на врезке "Параметры, обязательные при работе с индексированными представлениями". Они обязательны для применения индекса.USE AdventureWorks;
GO
IF EXISTS(SELECT 1 FROM sys.objects WHERE name =
N'v_SalesPerson2004ProductSummary')
DROP VIEW Sales.v_SalesPerson2004ProductSummary
GO
SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON
GO
CREATE VIEW Sales.v_SalesPerson2004ProductSummary
WITH SCHEMABINDING
AS
SELECT hdr.SalesPersonID
,cntc.FirstName AS SalesPersonFirstName
,cntc.LastName AS SalesPersonLastName
,prod.ProductID
,prod.Name AS ProductName
,COUNT_BIG(*) AS OrderLineCount
,SUM(dtl.OrderQty) as OrderQty
,SUM(dtl.LineTotal) as LineTotal
FROM Sales.SalesOrderHeader hdr
INNER JOIN Sales.SalesOrderDetail dtl
ON hdr.SalesOrderID = dtl.SalesOrderID
INNER JOIN HumanResources.Employee emp
ON hdr.SalesPersonID = emp.EmployeeID
INNER JOIN Person.Contact cntc
ON emp.ContactID = cntc.ContactID
INNER JOIN Production.Product prod
ON dtl.ProductID = prod.ProductID
WHERE hdr.OrderDate BETWEEN
CONVERT(DATETIME, "1/1/2004 00:00:00",120)
AND CONVERT(DATETIME,"12/31/2004 23:59:59",120)
GROUP BY hdr.SalesPersonID
,cntc.FirstName
,cntc.LastName
,prod.ProductID
,prod.Name;
GO
ProductID. Выполните следующий код (его можно найти среди файлов примеров под именем AddIndex.sql ).USE AdventureWorks
GO
CREATE UNIQUE CLUSTERED INDEX cidx_v_SalesPerson2004ProductSummary
ON Sales.v_SalesPerson2004ProductSummary
(SalesPersonID
,ProductID);
GO
Хотя использование индексированных представлений способно повысить производительность при извлечении итоговых данных из среды, оно связано с некоторыми обязательными параметрами и ограничениями. Представление, созданное в разделе "Создаем индексированное представление для итогов продаж" было разработано для обхода некоторых из таких ограничений.
ANSI_NULLS и QUOTED_IDENTIFIER должны быть установлены на ON. Параметр ANSI_NULLS должен быть включен также и для базовой таблицы, лежащей в основе представления.SCHEMA_BINDING. Оно объединит схему со схемами базовых таблиц.GROUP BY необходимо включить в список SELECT COUNT_BIG(*).GET-DATE(), поскольку она не является детерминированной. Необходимо также конвертировать даты в строковых форматах в даты в детерминированных форматах. В данном примере мы конвертируем строковое выражение в тип данных DATETIME при помощи канонического стандартного стиля ODBC (120).Следует иметь в виду еще несколько параметров и ограничений. Полный список можно найти в Электронной документации по SQL Server 2005 в теме "Создание индексированных представлений". Обязательно ознакомьтесь с этим списком, прежде чем приступать к использованию индексированных представлений, поскольку окончательный проект может оказаться слишком усложненным и не даст желательных преимуществ.
В предыдущих двух разделах мы узнали, как хранить итоговые архивные данные и осуществлять к ним доступ. Теперь мы познакомимся с некоторыми методами отслеживания меняющихся данных в самой таблице и за пределами исходной таблицы. Уровень аудита, который следует выбирать, зависит от того, что в действительности требуется узнать.
Можно выбрать простой уровень аудита, при котором будет записываться только дата изменения, или сложный уровень, при котором будет вестись полная запись изменения с возможностью восстановления, если возникнет необходимость. В последнем варианте используются столбцы аудита, таблицы аудита или их сочетание.
Преимущество аудита с помощью столбцов заключается в том, что контрольная информация размещается в той же таблице, что и данные. В табл. 7.1 перечислены некоторые столбцы аудита, которые обычно добавляются в таблицы.
| Отслеживаемые события | Типы данных | Комментарии |
|---|---|---|
INSERT, UPDATE, или DELETE |
DATETIME |
Используется для отслеживания даты и времени выполнения отслеживаемого действия. |
Обычно используется с функцией GETDATE() как значение по умолчанию, но значение может задаваться и вызывающим приложением. |
||
INSERT, UPDATE или DELETE |
VARCHAR |
Используется для отслеживания имени пользователя или приложения, выполняющего отслеживаемое действие. |
DELETE |
BIT/TINYINT |
Используется для того, чтобы пометить данные как удаляемые. Это может с большой эффективностью применяться в индексировании и фильтрации. |
По этой таблице можно сделать вывод, что изменения данных в действительности не протоколируются. Наиболее эффективный способ использования столбцов аудита – это отслеживание факта внесения изменения, времени изменения и лица или приложения, выполнившего это изменение. Можно использовать эти столбцы в любой комбинации, чтобы отслеживать изменения в записях в
Person.Address базы данных Adventure Works.Person.Address ) и определив события, которые будут отслеживаться, нужно решить, какие столбцы добавить в таблицу.ModifiedDate уже существует в таблице. Он будет отслеживать дату, показывающую, когда запись была в последний раз изменена или удалена.CreatedDate будет отслеживать, когда была создана запись. Тип данных этого столбца DATETIME, с использованием функции GETDATE() для предоставления текущей даты как значения по умолчанию.ModifiedBy —это столбец VARCHAR, который будет содержать имя пользователя или некоторые другие средства для идентификации пользователя или приложения, которые внесли изменения.IsDeleted - столбец с типом данных BIT, который будет использоваться для записи об удалении строки. Дата и пользователь будут отслеживаться через столбцы ModifiedDate и ModifiedBy. Если запись была удалена, этот столбец будет помечен, а в измененном столбце будут сведения о том, кто и когда удалил запись.Person.Address (этот код можно найти в файлах примеров под именем AlterTable.sql ).USE AdventureWorks
GO
ALTER TABLE Person.Address
ADD CreatedDate DATETIME NULL DEFAULT GETDATE()
,ModifiedBy VARCHAR(50) NULL
,IsDeleted BIT DEFAULT (0)
CreatedDate значение, показывающее, что столбец был создан до того, как был начат аудит. Чтобы задать значение CreatedDate, выполните следующий код:UPDATE Person.Address SET CreatedDate = "1/1/1980";
WHERE IsDeleted = 0
Теперь мы знаем, как использовать аудит для уведомления о сделанных изменениях. Однако единственное изменение, которое может быть легко отменено - это событие DELETE. Достаточно просто сбросить флаг IsDeleted, и данные будут снова доступны. Существует также возможность отменить событие CREATE, если об этом действии имеется достаточная информация. Однако если нужно иметь возможность полностью отслеживать состояние данных перед изменением, возможно, лучшим вариантом окажется использование таблиц аудита. Эту возможность следует использовать с осторожностью, потому что она может вызвать много проблем с обслуживанием и производительностью. Такие проблемы возникают потому, что приходится копировать данные в таблицу аудита и изменять их в исходной таблице. Для этого примера мы зададим аудит на базе таблицы в таблице Sales.Special . Цель – отслеживание любых изменений в этой таблице и обеспечение возможности отменить изменения после того, как они были зафи
ксированы.
Adventure Works таблицу Sales.SpecialOffer.Sales.SpecialOffer и выбрав из контекстного меню команды Script Table As, Create To, New Query Editor Window (Создать сценарий для таблицы, Используя CREATE, В новом окне редактора запросов). После этого откроется новое окно запроса с готовым для редактирования сценарием CREATE TABLE.CREATE.Sales.SpecialOffer на Sales.SpecialOffer_Audit.NULL. Благодаря этому таблица будет больше похожа на журнальную таблицу. В этом случае таблица аудита не должна мешать обычным операциям в таблице с самого начала. Это также должно упростить управление таблицей.| Имя столбца | Тип данных |
|---|---|
AuditModifiedDate |
DATETIME |
AuditType |
NVARCHAR(20) |
AdventureWorks. (Этот код можно найти в файлах примеров под именем CreateAuditTable.sql.)USE AdventureWorks;
GO
CREATE TABLE Sales.SpecialOffer_Audit(
SpecialOfferID INT NULL,
Description NVARCHAR(255) NULL,
DiscountPct SMALLMONEY NULL,
[Type] NVARCHAR(50) NULL,
Category NVARCHAR(50) NULL,
StartDate DATETIME NULL,
EndDate DATETIME NULL,
MinQty INT NULL,
MaxQty INT NULL,
rowguid UNIQUEIDENTIFIER NULL,
ModifiedDate DATETIME NULL,
AuditModifiedDate DATETIME NULL,
AuditType NVARCHAR(20) null
);
GO
Основные способы перемещения данных в таблицы аудита в SQL Server 2005 - это триггеры базы данных и новое предложение T-SQL OUTPUT. Однако новое предложение OUTPUT добавляет некоторые интересные возможности. В следующем разделе мы на примере изучим каждый из этих двух вариантов.
Sales.SpecialOffer триггер, который будет записывать предыдущее состояние данных в созданную нами таблицу Sales.SpecialOffer_Audit. Код, приведенный ниже – это пример синтаксической конструкции, которую можно использовать. (Этот код можно найти в файлах примеров под именем CreateTrigger.sql.) Введите и выполните код в окне нового запроса SQL Server Management Studio.USE AdventureWorks
GO
CREATE TRIGGER SpecialOfferUpdateAudit ON Sales.SpecialOffer
FOR UPDATE
AS
INSERT INTO Sales.SpecialOffer_Audit
(SpecialOfferID
,Description
,DiscountPct
,[Type]
,Category
,StartDate
,EndDate
,MinQty
,MaxQty
,rowguid
,ModifiedDate
,AuditModifiedDate
,AuditType)
SELECT TOP 1 d.SpecialOfferID
,d.Description
,d.DiscountPct
,d.[Type]
,d.Category
,d.StartDate
,d.EndDate
,d.MinQty
,d.MaxQty
,d.rowguid
,d.ModifiedDate
,GETDATE()
,'UPDATE'
FROM deleted d; GO
Sales.SpecialOffer, скорее всего, вам придется удалить триггер, который уже существует в таблице ( uSpecial Offer ). Необходимо сохранить сценарий для триггера, чтобы можно было использовать его в дальнейшем. Если этот триггер не удалить, то вы будете получать строки данных в таблице Sales.SpecialOffer_Audit при любом обновлении таблицы.Преимущество использования триггера заключается в том, что он будет захватывать любые обновления, которые произойдут в таблице, независимо от их источника. Это вариант аудита с полным охватом. Если речь идет о данных, которые изменяются без контроля с вашей стороны, то это превосходный вариант. Но если вы тщательно контролируете данные, которые заносятся в таблицу, особенно если это выполняется при помощи хранимых процедур, то в SQL Server 2005 есть новая возможность аудита изменений - предложение OUTPUT.
OUTPUT, каждое событие, которое нужно отслеживать, потребует разработки хранимых процедур и инструкций SQL, которые будут использоваться для обновления ( UPDATE ), вставки ( INSERT ) или удаления ( DELETE ) данных в отслеживаемых таблицах. Предложение OUTPUT предоставляет доступ к вставляемым и удаляемым таблицам в этих процедурах и инструкциях SQL. Теперь не обязательно использовать триггеры для доступа к данным. Представленный ниже код показывает пример использования предложения OUTPUT для аудита обновления в таблице SpecialOffer в таблице SpecialOffer_Audit. (Этот код можно найти в файлах примеров под именем UsingOutputClause.sql.) Введите и выполните данный код в окне нового запроса SQL Server Management Studio.OUTPUT должно вставлять свои данные в табличную переменную, во временную таблицу или - как в данном случае - в постоянную таблицу.USE AdventureWorks
GO
UPDATE Sales.SpecialOffer
SET description = "Big Mountain Tire Sale"
OUTPUT deleted.SpecialOfferID
,deleted.Description
,deleted.DiscountPct
,deleted.[Type]
,deleted.Category
,deleted.StartDate
,deleted.EndDate
,deleted.MinQty
,deleted.MaxQty
,deleted.rowguid
,deleted.ModifiedDate
,GETDATE()
,'UPDATE' INTO Sales.SpecialOffer_Audit
WHERE SpecialOfferID = 10
OUTPUT помещает измененные данные в рамках простого доступа в процессе изменения данных. В процессе операций UPDATE и DELETE доступен префикс DELETED. В процессе операций UPDATE и INSERT доступен префикс INSERTED. Обратите внимание на то, что оба префикса не могут быть доступными одновременно, в отличие от таблиц deleted и inserted, которые используются в триггерах. Эта взаимоисключающая доступность требует, чтобы различные операции обрабатывались по-разному для сбора нужных данных и помещения их в таблицы аудита.OUTPUT можно также использовать для возвращения значения из столбца IDENTITY в процессе операции INSERT.Теперь, когда у нас есть два варианта загрузки данных в таблицу аудита, можно подумать, для чего использовать эти данные. Поскольку все изменения в таблице сохраняются в таблице аудита, можно восстановить любые изменения данных, перезаписав текущие данные изменением, которое нужно сохранить. Таблица аудита может хранить несколько версий данных, поэтому чаще всего это придется делать вручную. Однако можно также создать обслуживающую хранимую процедуру для отмены самого последнего изменения.
UPDATE для перезаписи текущих данных изменением, которое следует восстановить в этой таблице. В данном примере придется использовать либо свойство rowguid, либо столбец SpecialOfferID в сочетании с AuditModifiedDate в качестве критерия для инструкции UPDATE, как показано ниже. (Этот код можно найти в файлах примеров под именем RecoveringChangedData.sql.) Введите и выполните этот код в окне нового запроса SQL Server Management Studio.— В этом сценарии нужно заменить AuditModifiedDate на
—AuditModifiedDate из таблицы SpecialOffer_Audit
USE AdventureWorks
GO
UPDATE Sales.SpecialOffer
SET Description = a.Description
,DiscountPct = a.DiscountPct
,Type = a.Type
,Category = a.Category
,StartDate = a.StartDate
,EndDate = a.EndDate
,MinQty = a.MinQty
,MaxQty = a.MaxQty
,rowguid = a.rowguid
,ModifiedDate = a.ModifiedDate
FROM Sales.SpecialOffer_Audit a
WHERE SpecialOffer.SpecialOfferID = 10
AND a.SpecialOfferID = 10
AND a.AuditModifiedDate = "2006-04-02 22:40:27.513"
Если у вас есть данные, которые нуждаются в регулярном восстановлении, можно инкапсулировать приведенный выше код в хранимую процедуру обслуживания. Однако если вы решите реализовать ее, у вас могут возникнуть проблемы с вводом восстановленных данных. Описанные варианты хорошо подходят для ограниченного количества строк в одной таблице. Если вы работаете с массовой высокопроизводительной загрузкой в нескольких таблицах, следует использовать моментальные снимки, о которых шла речь в первом разделе данной лекции.
Вы научились создавать моментальные снимки данных. Моментальные снимки могут эффективно использоваться для решения различных задач в процессе разработки, тестирования и производства. Можно использовать архивные данные для подведения итогов и анализа данных на определенных отрезках времени. Вы также научились выполнять аудит изменений данных и восстанавливать отдельные записи при помощи данных аудита. Сохраняя архивные данные и отслеживая изменения в базе данных, можно обеспечить целостность данных, используя возможность отмены отдельных изменений, не восстанавливая всю базу данных.
| Чтобы | Выполните следующие действия |
|---|---|
| Создать моментальный снимок базы данных | Воспользуйтесь инструкцией CREATE DATABASE с параметром AS SNAPSHOT OF. |
| Вернуться к моментальному снимку базы данных | Воспользуйтесь инструкцией RESTORE DATABASE с параметром FROM SNAPSHOT. |
| Удалить моментальный снимок базы данных | Воспользуйтесь инструкцией DROP DATABASE или удалите моментальный снимок базы данных через интерфейс SQL Server Management Studio. |
| Запланировать загрузку архивных данных | Создайте новое задание в агенте SQL Server и составьте расписание которое будет удовлетворять вашим потребностям. |
| Вывести итоговую информацию за определенный отрезок времени | Создайте индексированное представление для вывода итогов по одному или нескольким временным отрезкам. |
| Вести аудит изменений данных | Добавьте в таблицу столбцы аудита, в которых будет отслеживаться, кто и когда внес изменение. |
| Отслеживать все изменения данных и иметь возможность восстановить данные после ошибки ввода | Создайте и загрузите таблицу аудита либо при помощи триггеров, либо при помощи предложения OUTPUT. |
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.