web-dev-qa-db-ja.com

SQL Serverは読み取り専用ファイルグループのレコードを更新しましたか?

データウェアハウスに非常に大規模なデータベースがあり、メンテナンスとバックアップを管理するためにパーティションを実装しています。特定の期間のレコードは、最終的には月に1回、読み取り専用ファイルグループに移行されます。

時々、私たちのETLプロセスはすでにアーカイブに移行された古いレコードを更新しようとし、これらが失敗することを予期します。ただし、テスト環境の読み取り専用ファイルグループのパーティションにあるように見えても、テストのレコードが更新される最近の例が少なくとも2つあります(sys.partition_functionsおよびsys.partition_range_values)。

本番環境で同一のレコードを使用すると、レコードを更新しようとしたときに予期される障害が発生します。これまでに2回これをキャッチしましたが、更新は本番環境では失敗しますが、テストでは成功します(その逆はありません)。

関連する環境の事実:

  • SQL Server 2012 SP3 CU3(ビルド11.0.6537.0)
  • テストは開発者向けエディション、本番環境はエンタープライズ向け
  • リクエストに応じて他のユーザーに提供できます:現在、深刻な困惑しています...

UPDATE 2016-08-19

新しいレコードがどういうわけか一晩で更新されました。読み取り専用ファイルグループ上にあることを確認しました。同時に挿入されたレコードを更新できることがわかりました(つまり、読み取り専用ファイルグループの同じパーティションにもあります)。同じパーティションで単一のレコードを識別し、そのレコードを複数回更新できました。夜間に更新されたレコードを更新しようとすると、予期した障害が発生します。

UPDATE 2016-08-11

更新は、読み取り専用パーティションでのテストの夜間処理中にも発生し続けます。プロセスから同じレコードを更新しようとすると失敗します。以前にそれを更新したユーザーとしてログインしたときに、同じレコードを更新しようとして失敗しました。また、夜間のプロセスでまだ触れられていない同様のレコードを更新して、問題を再現することもできません。

UPDATE 2016-08-04

同じパーティションスキームを使用している別のテーブルで同じ動作の別の発生を発見したため、その単一のテーブルに限定されないことが今日発見されました。

UPDATE 2016-08-03

このMSDNスクリプト からスクリプトを実行すると、Kendra Littleのパーティションヘルパービューph.FilegroupDetailおよびph.ObjectDetail from このデモ 。問題のレコードはパーティション#2にあります(問題のレコードのパーティション列の値は2015-03-18です)

Filegroup     Low Boundary     UpperBoundary
Archive  (RO) NULL             1900-01-01
Archive  (RO) 1900-01-01       2015-04-01
ActiveFG (RW) 2015-04-01       2015-07-01
ActiveFG (RW) 2015-07-01       2015-10-01
ActiveFG (RW) 2015-10-01       2015-01-01
ActiveFG (RW) 2016-01-01       2016-04-01
ActiveFG (RW) 2016-04-01       2016-07-01
ActiveFG (RW) 2016-07-01       2016-10-01
ActiveFG (RW) 2016-10-01       2017-01-01
ActiveFG (RW) 2017-01-01       2115-01-01
ActiveFG (RW) 2115-01-01       NULL

パーティションにテーブルを配置するコード(他のインデックスはありません)

ALTER TABLE [dbo].[TABLE_NAME] ADD  CONSTRAINT [pk_TABLE_NAME] PRIMARY KEY CLUSTERED 
(
    [ETL_VERS_START_DTM] ASC,
    [ACCT_NO] ASC,
    [ACCT_TYPE] ASC
) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON ps_SmallTablesDate(ETL_VERS_START_DTM)

失敗するはずの更新ステートメント(Informatica経由):

UPDATE TABLE_NAME SET ETL_JOB_SEQ_NUM = ?, ETL_IUD_CD = ?, ETL_UPD_DTM = ?, ETL_DEL_DTM = ? WHERE ETL_VERS_START_DTM = ? AND ACCT_NO = ? AND ACCT_TYPE = ?
ETL_VERS_START_DTM (ETL_VERS_START_DTM:Date:): "03/17/2015 23:30:02.140000000"
ETL_JOB_SEQ_NUM (ETL_JOB_SEQ_NUM:Int:): "1173651"
ETL_IUD_CD (ETL_IUD_CD:Char.1:): "D"
ETL_UPD_DTM (ETL_UPD_DTM:Date:): "08/02/2016 02:32:45.000000000"
ETL_DEL_DTM (ETL_DEL_DTM:Date:): "08/02/2016 00:10:03.567000000"
ACCT_NO (ACCT_NO:Char.12:): "1234567890"
ACCT_TYPE (ACCT_TYPE:Char.3:): "OLN"

UPDATE 2017-02-21

ですから、今回の調査の結果、最も古いアクティブパーティションがアーカイブにマージされたときに、レコードのセクションがディスク上でアクティブファイルグループからアーカイブファイルグループに移動されないことがわかりました。次のクエリは、パーティション2のレコードがActiveFGにマップされていることを示していますが、実際のパーティションスキームを検査すると、それらの同じレコードをパーティション関数によってアーカイブファイルグループにソートする必要があることが示されています。

SELECT  OBJECT_NAME(P.[object_id]) ,
    P.index_id ,
    P.partition_number ,
    F.name ,
    F.filegroup_guid
FROM    sys.allocation_units AU
    JOIN sys.partitions P ON P.partition_id = AU.container_id
    JOIN sys.filegroups F ON F.data_space_id = AU.data_space_id
WHERE   P.partition_number IN ( 1, 2, 3 )
    AND P.[object_id] = OBJECT_ID('TABLE_NAME')
ORDER BY P.partition_number;

実際に使用中のデータベースのすべてのパーティションをバックアウトし、Microsoftチケットを処理するために壊れたバージョンのバージョンを保持しました。 DWチームと一緒にパーティション分割計画を修正する必要がありますが、もう一度試すことについては大胆ではありませんが認めます。

マイクロソフトはこの動作を再現することができなかったため、現時点ではチケットを使用しています。彼らはそれをすくめるだけで2014/2016に存在しないと想定する準備ができているように見えますか?私のシステムのバックアップから復元した後でも、データベースに存在し続けることができる私の能力にもかかわらず、彼らは彼らのラボでそれを複製するようには見えません。

8
toosuto

私は告白する必要があります。

若い頃、私はETLプロセスを構築しました。まず、読み取り専用ファイルグループを読み取り/書き込みに変更し、そのETL作業を実行してから、それらを読み取り専用に戻しました。

だから、私と同じように悪魔的な同僚がいたら(私は若いので、お金が必要でした)、次の方法でテストできます。

  1. 読み取り専用のファイルグループの名前を変更します。そのようにすると、ファイルグループを名前で変更するスクリプトがハードコードされている場合、スクリプトは失敗し、犯人を捕まえます。または、少し難しい:

  2. プロファイラーまたは拡張イベントを使用して、ALTER DATABASEを実行するすべてのユーザーを追跡します。

1
Brent Ozar