Aaronさんの記事は、インターンをテーブルに追加する質問に回答しますが、その後、新しいスキーマを使用するためにアプリケーションコードとストアドプロシージャを変更する必要があります。
...と思われるかもしれません。実際には、古いスキーマと一致するデータを返すVIEW
を作成することができます。INSERT
操作もビューでサポートされ、Messages
およびHugeTable
テーブルの子操作に変換されます。わかりやすくするために、テーブルにはInternedStrings
とExceptionLogs
という名前を使用します。だから、
古いテーブルには、このだった場合:
CREATE TABLE ExceptionLogs (
LogId int IDENTITY(1,1) NOT NULL PRIMARY KEY,
Message nvarchar(1024) NOT NULL,
ExceptionType nvarchar(512) NOT NULL,
StackTrace nvarchar(4096) NOT NULL
)
また、新しいテーブルは以下のとおりです。
CREATE TABLE InternedStrings (
StringId int IDENTITY(1,1) NOT NULL PRIMARY KEY,
Value nvarchar(max) NOT NULL
)
CREATE TABLE ExceptionLogs2 (-- note the new name
LogId int IDENTITY(1,1) NOT NULL PRIMARY KEY,
Message int NOT NULL,
ExceptionType int NOT NULL,
StackTrace int NOT NULL
)
は、より高速な値の検索を行うことがInternedStrings
にインデックスを追加します。
CREATE UNIQUE NONCLUSTERED INDEX IX_U_InternedStrings_Value ON InternedStrings (Value ASC)
また、VIEW
:
CREATE VIEW ExeptionLogs AS
SELECT
LogId,
MessageStrings .Value AS Message,
ExceptionTypeStrings.Value AS ExceptionType,
StackTraceStrings .Value AS StackTrace
FROM
ExceptionLogs2
INNER JOIN InternedStrings AS MessageStrings ON
MessageStrings.StringId = ExceptionLogs2.Message
INNER JOIN InternedStrings AS ExceptionTypeStrings ON
ExceptionTypeStrings.StringId = ExceptionLogs2.ExceptionType
INNER JOIN InternedStrings AS StackTraceStrings ON
StackTraceStrings.StringId = ExceptionLogs2.StackTrace
および未修飾のクライアントからINSERT
操作を処理するために:それは唯一の単一行の挿入をサポートし、完全に同時実行セーフではない、けれども前のデータが勝ったので:このTRIGGER
を向上させることができる
CREATE TRIGGER ExceptionLogsInsertHandler
ON ExceptionLogs INSTEAD OF INSERT AS
DECLARE @messageId int = SELECT StringId FROM InternedStrings WHERE Value = inserted.Message
IF @messageId IS NULL
BEGIN
INSERT INTO InternedStrings (Text) VALUES (inserted.Message)
SET @messageId = SCOPE_IDENTITY()
END
DECLARE @exceptionTypeId int = SELECT StringId FROM InternedStrings WHERE Value = inserted.ExceptionType
IF @exceptionTypeId IS NULL
BEGIN
INSERT INTO InternedStrings (Text) VALUES (inserted.ExceptionType)
SET @exceptionTypeId = SCOPE_IDENTITY()
END
DECLARE @stackTraceId int = SELECT StringId FROM InternedStrings WHERE Value = inserted.StackTrace
IF @stackTraceId IS NULL
BEGIN
INSERT INTO InternedStrings (Text) VALUES (inserted.StackTrace)
SET @stackTraceId = SCOPE_IDENTITY()
END
INSERT INTO ExceptionLogs2 (Message, ExceptionType, StackTrace)
VALUES (@messageId, @exceptionTypeId, @stackTraceId)
注意これは、データのわずかなリスクがあることを意味します。InternedStrings
テーブルにあります。また、UNIQUE
インデックスのため、挿入が失敗します。 TRANSACTION
を使用し、クエリを変更してholdlock
とupdlock
を使用するなど、これを処理するさまざまな方法があります。
データを正規化することと、文字列のインターンリング(値を繰り返すのではなく、繰り返し値への参照を使用すること)との概念的な違いはありません。そして、あなたが@Aaronが非常に大きなサイズの違いを知っていることをテストしたなら、私は賭けます。 –
サイズの変更は、メッセージ/タイプなどの選択性によって異なります。 –
概念的な違いはありませんが、実用的なものがたくさんあります。 *スキーマとクエリが変更されます * 、および潜在的にN個の挿入物を含む。 私は、繰り返しのある文字列は、組み込みの機能を持つと便利であることが十分一般的だと思います。 – Olmo