web-dev-qa-db-ja.com

SUBSTRINGを含むWHERE句を含む遅いクエリ

SQL Server 2016には次のクエリがあります。「ここにコードを入力」列のコードがないため、SUBSTRINGで検索する必要がありました。しかし、予想どおり遅いため、クエリは00:03:37で終了します。

with cte as
(
    -- De Incidente para Requisição
    select 
           cdchamado                       AS [Chamado]
          ,'De Incidente para Requisição'  AS [Tipo de Alteração]
          ,dtacompanhamento                AS [Alterado Em]
    from 
        [dbo].[hd_acompanhamento] 
    where 
        SUBSTRING(dsacompanhamento,45,36) = 'incidente para requisição de serviço'
    union
    -- De Requisição para Incidente  
    select 
           cdchamado                       AS [Chamado]
          ,'De Requisição para Incidente'  AS [Tipo de Alteração]
          ,dtacompanhamento                AS [Alterado Em]
    from 
        [dbo].[hd_acompanhamento] 
    where 
        SUBSTRING(dsacompanhamento,45,36) = 'requisição de serviço para incidente'
)
select * from cte

一時テーブルを作成し、必要なデータのみを挿入することを考えたので、このテーブルはSQL Serverエージェントのジョブによって更新されます。しかし、それが最善の解決策であるかどうかはわかりません。

2
Rafaells

IMO、計算列の主要な候補ではありませんが、UIまたはジョブを介してテーブルがどのように入力されるかを知ることが重要です。

もう1つのポイントは、述語がハードコーディングされている理由です。頻繁に変更できますか?

もう1つのポイントは、@ ErikがUNIONをポイントし、UNIONを削除するとクエリが向上することです。

with cte as
(
    -- De Incidente para Requisição
    select 
           cdchamado                       AS [Chamado]
          ,'De Incidente para Requisição'  AS [Tipo de Alteração]
          ,dtacompanhamento                AS [Alterado Em]
    from 
        [dbo].[hd_acompanhamento] 
    where 
        SUBSTRING(dsacompanhamento,45,36) = 'incidente para requisição de serviço'

)


    -- De Requisição para Incidente  
    select 
           cdchamado                       AS [Chamado]
          ,'De Requisição para Incidente'  AS [Tipo de Alteração]
          ,dtacompanhamento                AS [Alterado Em]
    from 
        [dbo].[hd_acompanhamento] 
    where 
        SUBSTRING(dsacompanhamento,45,36) = 'requisição de serviço para incidente'
        and not exists(select 1 from CTE 1 where hd_acompanhamento].somekeyCol = c.somekeyCol)
        union all
    select * from cte
1
KumarHarsh

このために2つの計算列を作成できます。

ALTER TABLE [dbo].[hd_acompanhamento]
ADD IsServiceRequest AS 
    CASE WHEN SUBSTRING(dsacompanhamento,45,36) = 'requisição de serviço para incidente' THEN 1 
    ELSE 0 END;

ALTER TABLE [dbo].[hd_acompanhamento]
ADD IsIncident AS 
    CASE WHEN SUBSTRING(dsacompanhamento,45,36) = 'incidente para requisição de serviço' THEN 1 
    ELSE 0 END;

そしてそれらにインデックスを付けます:

CREATE INDEX IX_IsServiceRequest 
ON [dbo].[hd_acompanhamento] (IsServiceRequest);

CREATE INDEX IX_IsIncident 
ON [dbo].[hd_acompanhamento] (IsIncident);

次に、クエリを次のように書き換えることができます。

with cte as
(
    -- De Incidente para Requisição
    select 
           cdchamado                       AS [Chamado]
          ,'De Incidente para Requisição'  AS [Tipo de Alteração]
          ,dtacompanhamento                AS [Alterado Em]
    from 
        [dbo].[hd_acompanhamento] 
    where 
        IsIncident = 1
    union
    -- De Requisição para Incidente  
    select 
           cdchamado                       AS [Chamado]
          ,'De Requisição para Incidente'  AS [Tipo de Alteração]
          ,dtacompanhamento                AS [Alterado Em]
    from 
        [dbo].[hd_acompanhamento] 
    where 
        IsServiceRequest = 1
)
select * from cte

これにより、サブストリング関数を実行しているテーブル全体をスキャンするのではなく、特定の行に対してクエリseekを実行できます。

キーのルックアップを回避するために、cdchamadoおよびdtacompanhamento列をインデックスに含まれる列として追加することもできます。それらのデータ型がわからないため、デフォルトでは含めませんでした。それらが大きなテキスト値である場合は、キールックアップのままにしておく方がよい場合があります。


別のオプションとして、1つの計算された列/インデックスのオーバーヘッドのみが必要な場合は、次のように組み合わせることができます。

ALTER TABLE [dbo].[hd_acompanhamento]
ADD ServiceRequestType AS 
CASE 
    WHEN SUBSTRING(dsacompanhamento,45,36) = 'requisição de serviço para incidente' THEN 1 
    WHEN SUBSTRING(dsacompanhamento,45,36) = 'incidente para requisição de serviço' THEN 2
    ELSE 0 
END;

次に、その1つの列だけにインデックスを付けて、ServiceType = 1およびServiceType = 2は、2つのクエリを一緒に結合します。 Erik Darling へのハットヒント。

4
Josh Darnell