web-dev-qa-db-ja.com

行を列に連結するためのより高速な方法が必要です-現在CTEを使用しています

現在、いくつかのテーブルからデータを取得するために作成したビューを使用しています。これに関する主な要因は、CTEと文字列を組み合わせて複数の行を1つの列に組み合わせる(複数回)ことで仕様を把握することです。ビューは機能しているが、ユーザーは最近、それが遅すぎると不満を述べている。
現在、ビューのセットアップは次のようになります。

;
With thing1 AS
(
SELECT DISTINCT
            /* huge block of code with joins and such  
            that gets the individual fields and concatenates  
            personnel names to one row */
)
,
thing2 AS
(
    SELECT  TaskName,
            Company,
            Lease,
            TaskBegin,
            TaskEnd,
            Field,
            Personnel,
            Invoice,
            InvDate,
            InvTot,
            ROW_NUMBER() OVER (Partition by TaskName ORDER BY [TaskName] ASC) rn
    FROM thing1 
)

SELECT  TaskName,
        Company,
        Lease,
        Field,
        ISNULL(Personnel, '') as 'Personnel',
        TaskBegin,
        TaskEnd,
        ISNULL (STUFF( (SELECT ', ' + Invoice 
                FROM thing1
                WHERE (thing1.TaskName = thing2.TaskName)
                AND thing2.rn = 1
                ORDER BY Invoice
                FOR XML PATH('')), 1, 1, ''), '') AS 'Invoice',
        ISNULL (STUFF( (SELECT ', ' + InvDate 
                FROM thing1
                WHERE (thing1.TaskName = thing2.TaskName)
                AND thing2.rn = 1
                ORDER BY Invoice
                FOR XML PATH('')), 1, 1, ''), '') AS 'InvoiceDate',
        ISNULL (STUFF( (SELECT ', ' + InvTot 
                FROM thing1
                WHERE (thing1.TaskName = thing2.TaskName)
                AND thing2.rn = 1
                ORDER BY Invoice
                FOR XML PATH('')), 1, 1, ''), '') AS 'InvoiceTotal'
    FROM thing2 WHERE rn = 1

GO

したがって、意図したとおりに機能します。問題は、Invoice、InvDate、およびInvTotを連結する最後のSELECTに到達すると、クエリが1秒を必要としないこと(つまり、thing2からの単純なSELECT)から、コースの実行に最大7秒かかることです。 (平均時間は約5秒です。)責任の一部は増え続けるデータベースにあると私はかなり確信しています。このビューは、レコードがはるかに少ないテスト環境ではるかに速くロードされます。

私の質問はこうです:DBでより速く、リソースをあまり消費しない方法でこれに対処することは可能ですか?

2
QuizzicalFerret

コードの問題は、CTEへの複数のアクセスとそこにあるすべての複雑なロジックにあるようです。 UNPIVOT/PIVOTを使用して、すべてを1つのパスで実行する必要があります。私はここで同様のことをしました: http://spaghettidba.com/2011/10/13/concatenating-multiple-columns-across-rows/
私の例では、異なる言語の文の連結が見つかりますが(正確には何をしているのかではありません)、同じテクニックを使用できるように思えます。

2
spaghettidba

あなたが持っているものは、レポートのために転置する必要があるEAVパターン(コードのブロックがほとんど同じテイクへの結合である)のようです。その場合、PIVOT機能を使用すると、CTEをより効率的にすることができます(コードの可読性と実行時の両方で)。 http://technet.Microsoft.com/en- us/library/ms177410(v = sql.105).aspx

0
David Spillett

あなたがそれを信じているならFOR XML PATHはビューを遅くする原因です。別のアプローチを使用して、行を単一の列に連結できます。この SQL Fiddle は、連結に再帰CTEを使用する方法を示しています。

Thing1とThing2の間にcte1、cte2、cte2、cte4を挿入し、最後の3つの列(FOR XML PATHを使用する場所)の代わりにcte4のInvoice、Invdate、InvTot列を直接使用するだけです。

0
cha