sql >> データベース >  >> RDS >> Database

主要なワイルドカードシークのフォローアップ#1

    前回の投稿で、「インデックスを取得して主要なワイルドカードを探す1つの方法」と述べました。私が推奨したフラグメントの維持に対処するためのトリガーが必要になります。何人かの人から、これらのトリガーを示すことができるかどうか尋ねられました。

    前の投稿から単純化するために、次のテーブルがあると仮定します。Companiesのセットと、CompanyNameFragmentsテーブルで、会社名の任意のサブストリングに対して疑似ワイルドカード検索を実行できます。

    CREATE TABLE dbo.Companies
    (
      CompanyID  int CONSTRAINT PK_Companies PRIMARY KEY,
      Name       nvarchar(100) NOT NULL
    );
    GO
     
    CREATE TABLE dbo.CompanyNameFragments
    (
      CompanyID int NOT NULL,
      Fragment  nvarchar(100) NOT NULL
    );
     
    CREATE CLUSTERED INDEX CIX_CNF ON dbo.CompanyNameFragments(Fragment, CompanyID);

    フラグメントを生成するためのこの関数を考えると(元の記事からの唯一の変更は、@inputを増やしたことです。 100文字をサポートするため):

    CREATE FUNCTION dbo.CreateStringFragments( @input nvarchar(100) )
    RETURNS TABLE WITH SCHEMABINDING
    AS
      RETURN 
      (
        WITH x(x) AS 
        (
          SELECT 1 UNION ALL SELECT x+1 FROM x WHERE x < (LEN(@input))
        )
        SELECT Fragment = SUBSTRING(@input, x, LEN(@input)) FROM x
      );
    GO

    3つの操作すべてを処理できる単一のトリガーを作成できます。

    CREATE TRIGGER dbo.Company_MaintainFragments
    ON dbo.Companies
    FOR INSERT, UPDATE, DELETE
    AS
    BEGIN
      SET NOCOUNT ON;
     
      DELETE f FROM dbo.CompanyNameFragments AS f
        INNER JOIN deleted AS d 
        ON f.CompanyID = d.CompanyID;
     
      INSERT dbo.CompanyNameFragments(CompanyID, Fragment)
        SELECT i.CompanyID, fn.Fragment
        FROM inserted AS i 
        CROSS APPLY dbo.CreateStringFragments(i.Name) AS fn;
    END
    GO

    これは、次の理由で発生した操作のタイプをチェックせずに機能します。

    • UPDATEまたはDELETEの場合、DELETEが発生します。UPDATEの場合、同じままであるフラグメントを一致させようとすることはありません。それらをすべて吹き飛ばすだけなので、まとめて交換できます。 INSERTの場合、deletedに行がないため、DELETEステートメントは効果がありません。 。
    • INSERTまたはUPDATEの場合、INSERTが発生します。 DELETEの場合、insertedに行がないため、INSERTステートメントは効果がありません。 。

    それでは、動作を確認するために、Companiesにいくつかの変更を加えましょう。 テーブルを作成してから、2つのテーブルを調べます。

    -- First, let's insert two companies 
    -- (table contents after insert shown in figure 1 below)
     
    INSERT dbo.Companies(Name) VALUES(N'Banana'), (N'Acme Corp');
     
    -- Now, let's update company 2 to 'Orange' 
    -- (table contents after update shown in figure 2 below):
     
    UPDATE dbo.Companies SET Name = N'Orange' WHERE CompanyID = 2;
     
    -- Finally, delete company #1 
    -- (table contents after delete shown in figure 3 below):
     
    DELETE dbo.Companies WHERE CompanyID = 1;
    図1: 初期テーブルの内容 図2: 更新後のテーブルの内容 図3: 削除後のテーブルの内容

    警告(参照整合性の人々向け)

    これら2つのテーブルの間に適切な外部キーを設定した場合、削除を処理するためにトリガーの代わりに使用する必要があることに注意してください。そうしないと、鶏と卵の問題が発生します。親の*後*まで待つことはできません。行が削除され、子行が削除されます。したがって、ON DELETE CASCADEを設定する必要があります (私は個人的には気に入らない傾向があります)、または2つのトリガーは次のようになります(UPDATEの場合、afterトリガーは引き続きDELETE / INSERTペアを実行する必要があります):

    CREATE TRIGGER dbo.Company_DeleteFragments
    ON dbo.Companies
    INSTEAD OF DELETE
    AS
    BEGIN
      SET NOCOUNT ON;
     
      DELETE f FROM dbo.CompanyNameFragments AS f
        INNER JOIN deleted AS d
        ON f.CompanyID = d.CompanyID;
     
      DELETE c FROM dbo.Companies AS c
        INNER JOIN deleted AS d
        ON c.CompanyID = d.CompanyID;
    END
    GO
     
    CREATE TRIGGER dbo.Company_MaintainFragments
    ON dbo.Companies
    FOR INSERT, UPDATE
    AS
    BEGIN
      SET NOCOUNT ON;
     
      DELETE f FROM dbo.CompanyNameFragments AS f
        INNER JOIN deleted AS d
        ON f.CompanyID = d.CompanyID;
     
      INSERT dbo.CompanyNameFragments(CompanyID, Fragment)
        SELECT i.CompanyID, fn.Fragment
        FROM inserted AS i
        CROSS APPLY dbo.CreateStringFragments(i.Name) AS fn;
    END
    GO

    概要

    この投稿は、シーク可能を維持するトリガーを設定するのがいかに簡単かを示すことを目的としています。 少なくとも中程度のサイズの文字列の場合、ワイルドカード検索を改善するための文字列フラグメント。今でも、この種のアイデアが奇抜なアイデアとして出くわすことは知っていますが、そこには良いユースケースがあると確信しているので、私はそれについて話し続けています。

    次の投稿では、この選択の影響を確認する方法を示します。代表的なワークロードを簡単に設定して、フラグメントを維持するためのリソースコストと、クエリ時のパフォーマンスの節約を比較できます。さまざまな文字列の長さとさまざまなワークロードのバランス(主に読み取りと主に書き込み)を調べて、スイートスポットと危険ゾーンを見つけようとします。


    1. OracleAppsのFND_LOBSテーブルについて知っておくべきこと

    2. MariaDB JSON_MERGE_PRESERVE()の説明

    3. Oracleデータベースに一時テーブルをどのように作成しますか?

    4. XMLデータをSQLServerデータベース列に細断処理す​​るための最良の方法