39

私は2つのテーブルを持っています、Table-AそしてTable-A-History

  • Table-A現在のデータ行が含まれます。
  • Table-A-History履歴データが含まれています

データの最新の行をに入れ、履歴行を含めたいと思いTable-AますTable-A-History

私はこれを達成するために2つの方法を考えることができます:

  1. 新しいデータ行が使用可能になるたびに、現在の行をからTable-Aに移動し、行を最新のデータでTable-A-History更新します(またはTable-Aを介して)insert into selectselect into table

    また

  2. 新しいデータ行が使用可能になるたびに、の行を更新Table-Aし、に新しい行を挿入しTable-A-Historyます。

パフォーマンスに関しては、方法1または2の方が優れていますか?これを達成するためのより良い別の方法はありますか?

4

8 に答える 8

65

基本的に、プライマリテーブルのサイズを小さく保ちながら、テーブルへの変更を追跡/監査しようとしています。

この問題を解決する方法はいくつかあります。それぞれの方法の短所と長所については、以下で説明します。

1-トリガーを使用したテーブルの監査。

テーブルの監査(挿入、更新、削除)を検討している場合は、不要なトランザクションを防止する方法を確認してください-SQLサタデースライドデッキ(コード付き)-http://craftydba.com/?page_id= 880。データはXMLとして保存されるため、必要に応じて、監査テーブルを埋めるトリガーは複数のテーブルからの情報を保持できます。したがって、必要に応じてXMLを解析することにより、アクションの削除を取り消すことができます。誰が、何が変更を加えたかを追跡します。

オプションで、独自のファイルグループに監査テーブルを設定できます。

Description:
    Table Triggers For (Insert, Update, Delete)
    Active table has current records.
    Audit (history) table for non-active records.

Pros:
    Active table has smaller # of records.
    Index in active table is small.
    Change is quickly reported in audit table.
    Tells you what change was made (ins, del, upd)

Cons:
    Have to join two tables to do historical reporting.
    Does not track schema changes.

2-レコードの効果的なデート

監査テーブルからデータを削除する予定がない場合は、行に削除済みのマークを付けて、永久に保持してください。人々のような多くのシステムは、レコードがアクティブでなくなったかどうかを示すために効果的な日付を使用します。BIの世界では、これはタイプ2次元テーブル(ゆっくりと変化する次元)と呼ばれます。データウェアハウス研究所の記事を参照してください。http://www.bidw.org/datawarehousing/scd-type-2/各レコードには開始日と終了日があります。

すべてのアクティブなレコードの終了日はnullです。

Description:
    Table Triggers For (Insert, Update, Delete)
    Main table has both active and historical records.

Pros:
    Historical reporting is easy.
    Change is quickly shown in main table.

Cons:
    Main table has a large # of records.
    Index of main table is large.
    Both active & history records in same filegroup.
    Does not tell you what change was made (ins, del, upd)
    Does not track schema changes.

3-データキャプチャの変更(エンタープライズ機能)。

Micorsoft SQL Server 2008では、変更データキャプチャ機能が導入されました。これは事後にLOGリーダーを使用してデータ変更(CDC)を追跡しますが、誰が、何が変更を行ったかなどが欠けています。MSDNの詳細-http://technet.microsoft.com/en-us/library/bb522489(v= sql.105 ).aspx

このソリューションは、実行中のCDCジョブに依存しています。SQLエージェントに問題があると、データの表示に遅延が発生します。

変更データキャプチャテーブルを参照してください。 http://technet.microsoft.com/en-us/library/bb500353(v=sql.105).aspx

Description:
    Enable change data capture

Pros:
    Do not need to add triggers or tables to capture data.
    Tells you what change was made (ins, del, upd) the _$operation field in 
    <user_defined_table_CT>
    Tracks schema changes.    

Cons:
    Only available in enterprise version.
    Since it reads the log after the fact, time delay in data showing up.
    The CDC tables do not track who or what made the change.
    Disabling CDC removes the tables (not nice)!
    Need to decode and use the _$update_mask to figure out what columns changed.

4-変更追跡機能(すべてのバージョン)。

Micorsoft SQL Server 2008では、変更追跡機能が導入されました。CDCとは異なり、すべてのバージョンが付属しています。ただし、何が起こったのかを把握するために呼び出す必要のあるTSQL関数が多数付属しています。

これは、アプリケーションを介して1つのデータソースをSQLサーバーと同期することを目的として設計されました。TechNetには同期フレーム全体の作業があります。

http://msdn.microsoft.com/en-us/library/bb933874.aspx http://msdn.microsoft.com/en-us/library/bb933994.aspx http://technet.microsoft.com/en- us / library / bb934145(v = sql.105).aspx

CDCとは異なり、変更がパージされるまでデータベースに保持される期間を指定します。また、挿入と削除はデータを記録しません。更新では、変更されたフィールドのみが記録されます。

SQL Serverソースを別のターゲットに同期しているため、これは正常に機能します。変更を把握するために定期的なジョブを作成しない限り、監査には適していません。

その情報はまだどこかに保存する必要があります。

Description:
    Enable change tracking

Cons:
    Not a good auditing solution

最初の3つのソリューションは、監査に役立ちます。私は自分の環境で広く使用しているので、最初のソリューションが好きです。

心から

ジョン

プレゼンテーションからのコードスニペット(自動車データベース)

-- 
-- 7 - Auditing data changes (table for DML trigger)
-- 


-- Delete existing table
IF OBJECT_ID('[AUDIT].[LOG_TABLE_CHANGES]') IS NOT NULL 
  DROP TABLE [AUDIT].[LOG_TABLE_CHANGES]
GO


-- Add the table
CREATE TABLE [AUDIT].[LOG_TABLE_CHANGES]
(
  [CHG_ID] [numeric](18, 0) IDENTITY(1,1) NOT NULL,
  [CHG_DATE] [datetime] NOT NULL,
  [CHG_TYPE] [varchar](20) NOT NULL,
  [CHG_BY] [nvarchar](256) NOT NULL,
  [APP_NAME] [nvarchar](128) NOT NULL,
  [HOST_NAME] [nvarchar](128) NOT NULL,
  [SCHEMA_NAME] [sysname] NOT NULL,
  [OBJECT_NAME] [sysname] NOT NULL,
  [XML_RECSET] [xml] NULL,
 CONSTRAINT [PK_LTC_CHG_ID] PRIMARY KEY CLUSTERED ([CHG_ID] ASC)
) ON [PRIMARY]
GO

-- Add defaults for key information
ALTER TABLE [AUDIT].[LOG_TABLE_CHANGES] ADD CONSTRAINT [DF_LTC_CHG_DATE] DEFAULT (getdate()) FOR [CHG_DATE];
ALTER TABLE [AUDIT].[LOG_TABLE_CHANGES] ADD CONSTRAINT [DF_LTC_CHG_TYPE] DEFAULT ('') FOR [CHG_TYPE];
ALTER TABLE [AUDIT].[LOG_TABLE_CHANGES] ADD CONSTRAINT [DF_LTC_CHG_BY] DEFAULT (coalesce(suser_sname(),'?')) FOR [CHG_BY];
ALTER TABLE [AUDIT].[LOG_TABLE_CHANGES] ADD CONSTRAINT [DF_LTC_APP_NAME] DEFAULT (coalesce(app_name(),'?')) FOR [APP_NAME];
ALTER TABLE [AUDIT].[LOG_TABLE_CHANGES] ADD CONSTRAINT [DF_LTC_HOST_NAME] DEFAULT (coalesce(host_name(),'?')) FOR [HOST_NAME];
GO



--
--  8 - Make DML trigger to capture changes
--


-- Delete existing trigger
IF OBJECT_ID('[ACTIVE].[TRG_FLUID_DATA]') IS NOT NULL 
  DROP TRIGGER [ACTIVE].[TRG_FLUID_DATA]
GO

-- Add trigger to log all changes
CREATE TRIGGER [ACTIVE].[TRG_FLUID_DATA] ON [ACTIVE].[CARS_BY_COUNTRY]
  FOR INSERT, UPDATE, DELETE AS
BEGIN

  -- Detect inserts
  IF EXISTS (select * from inserted) AND NOT EXISTS (select * from deleted)
  BEGIN
    INSERT [AUDIT].[LOG_TABLE_CHANGES] ([CHG_TYPE], [SCHEMA_NAME], [OBJECT_NAME], [XML_RECSET])
    SELECT 'INSERT', '[ACTIVE]', '[CARS_BY_COUNTRY]', (SELECT * FROM inserted as Record for xml auto, elements , root('RecordSet'), type)
    RETURN;
  END

  -- Detect deletes
  IF EXISTS (select * from deleted) AND NOT EXISTS (select * from inserted)
  BEGIN
    INSERT [AUDIT].[LOG_TABLE_CHANGES] ([CHG_TYPE], [SCHEMA_NAME], [OBJECT_NAME], [XML_RECSET])
    SELECT 'DELETE', '[ACTIVE]', '[CARS_BY_COUNTRY]', (SELECT * FROM deleted as Record for xml auto, elements , root('RecordSet'), type)
    RETURN;
  END

  -- Update inserts
  IF EXISTS (select * from inserted) AND EXISTS (select * from deleted)
  BEGIN
    INSERT [AUDIT].[LOG_TABLE_CHANGES] ([CHG_TYPE], [SCHEMA_NAME], [OBJECT_NAME], [XML_RECSET])
    SELECT 'UPDATE', '[ACTIVE]', '[CARS_BY_COUNTRY]', (SELECT * FROM deleted as Record for xml auto, elements , root('RecordSet'), type)
    RETURN;
  END

END;
GO



--
--  9 - Test DML trigger by updating, deleting and inserting data
--

-- Execute an update
UPDATE [ACTIVE].[CARS_BY_COUNTRY]
SET COUNTRY_NAME = 'Czech Republic'
WHERE COUNTRY_ID = 8
GO

-- Remove all data
DELETE FROM [ACTIVE].[CARS_BY_COUNTRY];
GO

-- Execute the load
EXECUTE [ACTIVE].[USP_LOAD_CARS_BY_COUNTRY];
GO 

-- Show the audit trail
SELECT * FROM [AUDIT].[LOG_TABLE_CHANGES]
GO

-- Disable the trigger
ALTER TABLE [ACTIVE].[CARS_BY_COUNTRY] DISABLE TRIGGER [TRG_FLUID_DATA];

**監査テーブルのルックアンドフィール**

ここに画像の説明を入力してください

于 2013-10-02T18:42:25.667 に答える
28

変更のログ記録は、ベーステーブルのトリガーを使用して変更をログテーブルに記録するために一般的に行ったことです。ログテーブルには、データベースユーザー、アクション、および日付/時刻を記録するための追加の列があります。

create trigger Table-A_LogDelete on dbo.Table-A
  for delete
as
  declare @Now as DateTime = GetDate()
  set nocount on
  insert into Table-A-History
    select SUser_SName(), 'delete-deleted', @Now, *
      from deleted
go
exec sp_settriggerorder @triggername = 'Table-A_LogDelete', @order = 'last', @stmttype = 'delete'
go
create trigger Table-A_LogInsert on dbo.Table-A
  for insert
as
  declare @Now as DateTime = GetDate()
  set nocount on
  insert into Table-A-History
    select SUser_SName(), 'insert-inserted', @Now, *
      from inserted
go
exec sp_settriggerorder @triggername = 'Table-A_LogInsert', @order = 'last', @stmttype = 'insert'
go
create trigger Table-A_LogUpdate on dbo.Table-A
  for update
as
  declare @Now as DateTime = GetDate()
  set nocount on
  insert into Table-A-History
    select SUser_SName(), 'update-deleted', @Now, *
      from deleted
  insert into Table-A-History
    select SUser_SName(), 'update-inserted', @Now, *
      from inserted
go
exec sp_settriggerorder @triggername = 'Table-A_LogUpdate', @order = 'last', @stmttype = 'update'

ロギングトリガーは常に最後に起動するように設定する必要があります。そうしないと、後続のトリガーが元のトランザクションをロールバックする可能性がありますが、ログテーブルはすでに更新されています。これは紛らわしい状況です。

于 2012-08-09T20:22:12.187 に答える
28

SQL Serverの最近のバージョン(2016以降およびAzure)には、ファーストクラスの機能として、要求された正確な機能を提供する一時テーブルがあります。 https://docs.microsoft.com/en-us/sql/relational-databases/tables/temporal-tables

Microsoftの誰かがおそらくこのページを読んだでしょう。:)

于 2017-05-02T02:17:58.487 に答える
4

より多くのスペースを消費しますが、最新のレコードを含む履歴テーブルを用意しておくと、レポートを作成したり、変更がどのようにいつ発生したかを確認したりする手間を省くことができます。私の意見では、考える価値のあることです。

パフォーマンスに関しては、同じであると思います。ただし、2つのテーブル間で参照整合性を使用しているため、非履歴テーブルからレコード(オプション1の「移動」)を削除したくないことは確かです。

于 2012-08-09T20:00:14.443 に答える
4

方法3はどうですか。Table-Aに対してビューを作成しTable-A-Historyます。に挿入しTable-A-History、適切なフィルタリングロジックでを生成しTable-Aます。そうすれば、1つのテーブルに挿入するだけです。

于 2012-08-09T19:51:01.397 に答える
2

方法1をお勧め します。さらに、必要に応じて
、履歴テーブルにも現在のレコードを保持します。

于 2012-08-09T20:00:36.187 に答える
2

オプション1はOKです。しかし、方法4もあります:)

  1. テーブルに新しいレコードを挿入し、

  2. mysqlスケジューラを使用して、古いレコードを定期的にアーカイブテーブルに移動します。夜間など、負荷が最小の時間にデータアーカイブをスケジュールできます。

于 2012-08-09T20:13:02.823 に答える
0

次のように、この問題を解決するためのプロシージャまたはジョブを作成するだけです。

 create procedure [dbo].[sp_LoadNewData]
 AS
INSERT INTO [dbo].[Table-A-History]
 (
 [1.Column Name], [2.Column Name], [3.Column Name], [4.Column Name]
 )    
 SELECT [1.Column Name], [2.Column Name], [3.Column Name], [4.Column Name]
 FROM dbo.[Table-A] S

 WHERE NOT EXISTS
 (
 SELECT  * FROM [dbo].[Table-A-History] D WHERE D.[1.Column Name] =S.[1.Column Name]
 )

注:[1。列名]はテーブルの共通列です。

于 2020-10-23T14:35:23.543 に答える