私はデータベースソリューションについてプログラマと協力しています。彼らは計算された列を追加して、古いクエリ、プロシージャ、システムの古いキーを模倣し、インデックスを付けたいと考えています。新しいキーはGUIDSになります。
これを行うには、値を作成して永続化する計算列の関数を作成します。列を永続化させません。アイデアについての温かいあいまいさはなく、テクニックに関するWeb上の情報も見つかりません(それはテクニックですか?)。
代わりにトリガーを追加する必要があると思います。誰かアイデアはありますか?
関数は次のように実行されます。
(SELECT [INT Identity field] FROM TABLE WHERE [GUID COLUMN] = @GUIDKEY
GUIDに基づいてINT Identityフィールドを返します。
これは、関連するテーブルへの挿入時に実行されます。 SOテーブル1が主キーを保持している場合、関連するテーブル2が(GUID渡された)を使用して)更新され、テーブル1からキーを取得して挿入しますそれを表2に入れます。
これがなぜテーブルの列である必要があるのかまだ理解できません。
クエリが実際にそれを必要とするとき(そしてそのときだけ)に相互適用するテーブル値関数を作成しないのはなぜですか。古いキーは決して変更されないため、とにかく計算したり永続化したりする必要はありません。
古いキーを複数の場所に保存したい場合(そして、この種の決定を行うべきではない人々がすでにこの種の決定を行っているように思われる場合)、トリガーでルックアップを実行し、書き込み時にそれを入力します。 。次に、それはテーブル内の静的列です。
これを容易にするためにテーブル値関数を強くお勧めします。これにより、ループを記述したり、スカラー値関数を呼び出したりすることなく、複数行の操作を処理するようにトリガーを記述できます。すべての行で繰り返します。
これらがどれほど似ているかを示すためだけに(そして、「気に入らない」リード開発者に質問します):
-- bad, slow, painful row-by-row
CREATE FUNCTION dbo.GetIDByGUID
(
@GuidKey uniqueidentifier
)
RETURNS int
AS
BEGIN
RETURN (SELECT $IDENTITY FROM dbo.tablename WHERE guid_column = @GuidKey);
END
GO
-- in the trigger:
UPDATE r SET oldkey = dbo.GetIDByGUID(i.guid_column)
FROM dbo.related AS r
INNER JOIN inserted AS i
ON r.guid_column = i.guid_column;
これで、テーブル値関数がある場合、コードは非常に似ていますが、パフォーマンスは複数行の操作ではるかに向上し、単一行の操作とほぼ同じであることがわかります。
-- ah, much better
ALTER FUNCTION dbo.GetIDByGUID_TVF
(
@GuidKey uniqueidentifier
)
RETURNS TABLE
AS
RETURN (SELECT id = $IDENTITY FROM dbo.tablename WHERE guid_column = @GuidKey);
GO
-- in the trigger:
UPDATE r SET oldkey = f.id
FROM dbo.related AS r
INNER JOIN inserted AS i
ON r.guid_column = i.guid_column
CROSS APPLY dbo.GetIDByGUID_TVF(i.guid_column) AS f;
これを行うには関数または計算列が必要だと思う理由がわかりません。デフォルト値を使用してテーブルに新しい列を追加し、必要に応じてインデックスを付けることができます。
CREATE TABLE dbo.whatever ( Id INT );
ALTER TABLE dbo.whatever
ADD YourMom UNIQUEIDENTIFIER
DEFAULT NEWSEQUENTIALID();
CREATE INDEX ix_whatever ON dbo.whatever (YourMom);
質問を更新したので、これが本当にひどい考えに対処しましょう。例を少し簡略化します。
CREATE TABLE dbo.whatever ( Id INT PRIMARY KEY);
CREATE TABLE dbo.ennui ( Id INT PRIMARY KEY, meh INT );
GO
CREATE FUNCTION dbo.BadIdea ( @notguido INT )
RETURNS INT
WITH SCHEMABINDING, RETURNS NULL ON NULL INPUT
AS
BEGIN
DECLARE @out INT;
SELECT @out = ( SELECT e.Id FROM dbo.ennui AS e WHERE e.meh = @notguido );
RETURN @out;
END;
GO
ALTER TABLE dbo.whatever ADD ishygddt AS dbo.BadIdea(Id)
/*Will fail*/
ALTER TABLE dbo.whatever ALTER COLUMN ishygddt ADD PERSISTED;
/*Will fail*/
CREATE INDEX ix_whatever ON dbo.whatever (ishygddt);
スカラー関数( [〜#〜] schemabinding [〜#〜] を使用した確定的な列でも)に基づいて計算列を永続化しようとすると、データアクセスを実行すると失敗します。
メッセージ4934、レベル16、状態3、行23テーブル 'whatever'の計算された列 'ishygddt'は、列がユーザーまたはシステムデータにアクセスするため、保持できません。
インデックスを作成することもできません。
メッセージ2709、レベル16、状態1、行25テーブル 'dbo.whatever'の列 'ishygddt'は、ユーザーまたはシステムのデータアクセスを行うため、インデックスまたは統計で、またはパーティションキーとして使用できません。
また、関数はデータを取得するために行ごとに実行され、 テーブルに対するすべてのクエリを強制的に逐次実行する になるため、多くの問題に遭遇します。
関数が参照するテーブルのデータを変更し、計算列の関数を呼び出すテーブルからデータを選択する場合、関数がクエリにデータを返さないようにブロックされている、非常に混乱するブロックシナリオが発生する可能性があります一見無関係なテーブルに。
これは至る所で悪い考えです。アーロンは彼のコメントで私が最高のアドバイスだと思うものを与えました:
クエリが実際にそれを必要とするとき(そしてそのときだけ)に相互適用するテーブル値関数を作成しないのはなぜですか。古いキーは決して変更されないため、とにかく計算したり永続化したりする必要はありません。古いキーを複数の場所に保存したい場合は、トリガーで検索を実行してください。
BOLの永続的な計算列 、および関連する 計算列のインデックス について読むことができます。
永続的な計算列で使用できる式には制限があります。 「PERSISTEDが指定されている場合、式は確定的でなければなりません。」
私が正しく理解していれば、次のようになります。
t
と呼びましょう。t
にはguid列があります。これをgc
と呼びましょう。t.gc
の値を異なるタイプの異なるキー値にマッピングするルックアップであり、レガシーコードで使用されます。テーブルlt
とレガシーキー列lk
を呼び出します。lt.lk
をt
にt.lk
として表示し、レガシーコードが引き続き使用できるようにする必要があります。ビューを使用して調査します。
t
をt_base
のような名前に変更します。t_base
をt
に結合し、t_base
とlt.lk
の列を返すlt
という名前のビューを作成します。開発者が解決しようとしている問題は、あるデータ型から新しいデータ型へのかなり標準的な移行の問題です。データベースが最初に設計されたときに予期されなかった新しい問題があります。つまり、データベース間でデータを同期する必要があります。これは、特にデータ型が多くのコードで信頼されている場合、コストのかかる作業になる傾向があります。コスト削減策を探すことは完全に不合理ではありません。
まず第一に、問題はおそらく数学的に扱いにくいことを理解することが重要です。 A GUIDまたはUUIDは、128ビット、つまり16バイトの数値です。IDENTITY
列のサイズは、使用されるデータ型によって異なりますが、通常はINT
(32ビット、4バイト);場合によってはBIGINT
(64バイト、8バイト)が使用されます。GUIDの範囲をINTの範囲またはBIGINTに完全にマッピングする数学的な方法はありません。列がDECIMAL(38,0)
であれば数学的に可能ですが、これは十分な大きさですが、これは非常にまれです。
GUIDをDECIMAL
型にマップすることが可能であっても、それが実用的であるとは限りません。事実上誰もこれを行わないので、マッピングが正しく機能することを保証するために時間(=お金)を費やす必要があります。彼らのソリューションは、奇妙で診断が難しいバグを作成するという重要なリスクをもたらします。
さらに、ソリューションでデータの既存のIDを保持することはできません。これは、IDを含むエンドユーザーのブックマークを破壊する可能性があります。
最後に、それらの解決策は固定されている可能性があります。上記のすべての理由により、これは良い習慣ではありませんが、もしそれが発生した場合、整数キーをすべて新しいもので使い続けるのは「簡単」であるため、すぐにそれから離れることができない可能性があります。コード。
既存のシステムに同期を導入する比較的標準的なアプローチは、add新しい一意のIDです。この新しいIDは、古い既存のキーに加えて、データに追加されます。次に、代理キーは同期されません。
これにはいくつかの大きな利点があります。
このアプローチには、2つの小さな問題があります。
ただし、これらの問題はどちらも管理可能であり、すべてをGUIDに切り替えるのが非常に高額である場合は、トレードオフとして妥当です。
また、このソリューションでは、実行を要求しているクエリを正確に有効にしたことにも注意してください。
これでは今は手遅れになるかもしれませんが、今後は良い情報だと思います。