1

テーブル データの再利用について質問がありますが、渡す必要のあるパラメーターがあるため、このシナリオではビューが機能しません。基本的に、システムのこの部分ではtravellerid、プロシージャに を送信し、その特定の旅行者のためにアレンジャーが戻ってきました。どのアレンジャーを返すことができるかを決定するために使用される約 7 つのビジネス ルールがあり、それらは相互に排他的であるため、これらのオプションのルールに対応するために、派生クエリ内で一連の UNION を使用しました。これはうまく機能しており、パフォーマンスはかなり大きなデータベース全体で良好に見えますが、システムの約 4 つの他の部分でこれらのルール (UNIONS) を再利用する必要があります。

最初にこれらの UNIONS を使用して VIEW を作成しようとしましたが、各 UNION のロジックが異なり、パラメーター要件が異なるために機能しませんでした。そのため、関数でこの問題を解決できるのではないかと考えていました。ビジネス ルールに基づいて、パラメーター@travelleridとして取り、リストを返す関数を作成した場合、これは理想的で高速なソリューションでしょうか? arrangerid現在、外部クエリで UNION ALL と DISTINCT を使用しています。これは、データの一意性のために UNION を使用するよりもはるかに高速であることが証明されたためです。

以下のビジネス ルールを使用した現在の手順 (SQL Server 2008):

CREATE PROCEDURE [dbo].[getArrangersForTraveller]
   @travellerid int
AS
  DECLARE @costcentreid int
  DECLARE @departmentid int

-- Shorthand the traveller costcentre and department for use in queries below
SET @costcentreid = (SELECT costcentreid FROM traveller WHERE id = @travellerid)
SET @departmentid = (SELECT departmentid FROM traveller WHERE id = @travellerid)


SELECT DISTINCT t.id, t.firstname, t.lastname, ti.name AS title, dv.preferred
FROM traveller t

INNER JOIN title ti ON t.titleid = ti.id
     INNER JOIN

     (

            -- Get Preferred Arrangers linked to Department Groups
            SELECT dg.arrangerid as id
            FROM departmentGroup dg 
                INNER JOIN department_departmentGroup ddg 
                ON (dg.id = ddg.departmentGroupId AND ddg.departmentid = @departmentid)

            UNION ALL

            -- Get Preferred Arrangers linked to Cost Centre Groups
            SELECT cg.arrangerid as id
            FROM costCentreGroup cg 
                INNER JOIN costcentre_costCentreGroup ccg 
                ON (cg.id = ccg.costCentreGroupId AND ccg.costcentreid = @costcentreid)

            UNION ALL

            -- If Cost Centre Group has a linked department and this department matches 
            -- the travel arrangers department then return these travel arrangers as well     
            SELECT t3.id
            FROM costCentreGroup cg1

                INNER JOIN costcentre_costCentreGroup ccg1 
                ON (cg1.id = ccg1.costCentreGroupId AND ccg1.costcentreid = @costcentreid) 

                INNER JOIN traveller t3  
                ON t3.departmentid = cg1.departmentid    

            WHERE  t3.accesslevelid > 1       

            UNION ALL

            -- Get Direct linked travel arrangers      
            SELECT t1.travelarrangerid as id
            FROM   travelarranger_traveller t1
            WHERE  t1.travellerid = @travellerid

            UNION ALL

            -- Get Cost Centre linked arrangers
            SELECT tc.travelarrangerid as id
            FROM   travelArranger_costcentre tc 
            WHERE  tc.costcentreid = @costcentreid

            UNION ALL

            -- Get Department linked arrangers
            SELECT td.travelarrangerid
            FROM   travelArranger_department td 
            WHERE  td.departmentid = @departmentid

            UNION ALL

            -- Get Company flagged arrangers 
            SELECT t2.id
            FROM   traveller t2
                   INNER JOIN company c ON t2.companyid = c.id

            WHERE  t2.accesslevelid > 1       
            AND ((c.allowTravelArrangerDepartmentAccess = 1 AND t2.departmentid = @departmentid)
            OR  (c.allowTravelArrangerCostCentreAccess = 1 AND t2.costcentreid = @costcentreid))

     ) as dv ON dv.id = t.id

WHERE t.accessLevelid > 1 -- arranger or manager
AND t.isenabled = 1
ORDER BY dv.preferred DESC, t.lastname, t.firstname;
4

1 に答える 1

2

最初にこれらの UNION を使用して VIEW を作成しようとしましたが、各 UNION のロジックが異なり、パラメーター要件が異なるために機能しませんでした。そのため、関数でこの問題を解決できるのではないかと考えていました。パラメータ @travellerid として取り、ビジネス ルールに基づいて Arrangerid のリストを返す関数を作成した場合、これは理想的で高速なソリューションでしょうか?

あなたは手続き型/OO プログラミングを考えていますが、SQL は SET ベースです。
関数は機能しますが、決定基準などに関数を使用するときにインデックスを使用できないことを保証します。非マテリアライズド ビューはわずかに優れています。SQL Server には、インデックス付きビュー (AKA マテリアライズド ビュー) を使用するオプションがありますが、制約があることで有名です。これはモジュラー プログラミングの概念に反しますが、SQL をモジュール化しようとせず、実際に必要なものだけを使用するほど、SQL はうまく機能します。

クエリを書き直しましたが、外側のクエリでは dv.preferred 列が参照されていますが、内側のクエリには存在しないことに気付きました。これdvはさまざまなテーブルとロジックの集合体であるidため、値がどのテーブルから来たかを知る必要があるため、返される値は内部クエリの外部の実際の値ではありません。そうは言っても、ここにあります:

SELECT t.id, t.firstname, t.lastname, ti.name AS title /*, dv.preferred */
  FROM TRAVELLER t
  JOIN title ti ON t.titleid = ti.id
 WHERE (EXISTS(SELECT NULL -- Get Preferred Arrangers linked to Department Groups
                 FROM departmentGroup dg 
                 JOIN department_departmentGroup ddg ON ddg.departmentGroupId = dg.id 
                                                    AND ddg.departmentid = @departmentid
                WHERE dg.arrangerid = t.id)
    OR EXISTS(SELECT NULL -- Get Preferred Arrangers linked to Cost Centre Groups
                FROM costCentreGroup cg 
                JOIN costcentre_costCentreGroup ccg ON ccg.costCentreGroupId = cg.id 
                                                   AND ccg.costcentreid = @costcentreid
               WHERE cg.arrangerid = t.id)
    OR EXISTS(SELECT NULL -- If Cost Centre Group has a linked department and this department matches the travel arrangers department then return these travel arrangers as well     
                FROM costCentreGroup cg1
                JOIN costcentre_costCentreGroup ccg1 ON ccg1.costCentreGroupId = cg1.id 
                                                    AND ccg1.costcentreid = @costcentreid
                JOIN traveller t3 ON t3.departmentid = cg1.departmentid    
                                 AND  t3.accesslevelid > 1
               WHERE t3.id = t.id)
    OR EXISTS(SELECT NULL  -- Get Direct linked travel arrangers    
                FROM travelarranger_traveller t1
               WHERE t1.travellerid = @travellerid
                 AND t1.travelarrangerid = t.id)
    OR EXISTS(SELECT NULL -- Get Cost Centre linked arrangers
                FROM travelArranger_costcentre tc 
               WHERE tc.costcentreid = @costcentreid
                 AND tc.travelarrangerid = t.id)
    OR EXISTS(SELECT NULL -- Get Department linked arrangers
                FROM travelArranger_department td 
               WHERE td.departmentid = @departmentid
                 AND td.travelarrangerid = t.id)
    OR EXISTS(SELECT NULL -- Get Company flagged arrangers 
                FROM traveller t2
                JOIN company c ON t2.companyid = c.id
                              AND t2.accesslevelid > 1       
               WHERE (   (c.allowTravelArrangerDepartmentAccess = 1 AND t2.departmentid = @departmentid)
                      OR (c.allowTravelArrangerCostCentreAccess = 1 AND t2.costcentreid = @costcentreid))
                 AND t2.id = t.id))
   AND t.accessLevelid > 1 -- arranger or manager
   AND t.isenabled = 1
ORDER BY /*dv.preferred DESC,*/ t.lastname, t.firstname;

サブクエリ (IN、EXISTS) を使用すると、親レコードに複数の子レコードが関連付けられている場合に、結合の使用に伴う重複の問題が軽減されます。

于 2010-10-07T01:48:45.213 に答える