Должен ли я использовать функцию T-SQL, представление или сохраненный процесс? - PullRequest
1 голос
/ 07 октября 2010

У меня есть вопрос о повторном использовании данных таблицы, но представление не будет работать в этом сценарии, так как у меня есть параметр, который необходимо передать. В основном для этой части системы требуется отправить travelleridпроцедура и список организаторов возвращаются для этого конкретного путешественника.Существует около 7 бизнес-правил, которые используются для определения того, какие аранжировщики могут быть возвращены, и они являются взаимоисключающими, поэтому для соответствия этим необязательным правилам я использовал серию UNIONS внутри производного запроса.Это работает хорошо, и производительность кажется хорошей для довольно большой базы данных, однако мне нужно повторно использовать эти правила (UNIONS) примерно в 4 других частях системы.

Изначально я пытался создать VIEW с этими UNION, но это не сработало из-за различий в логике в каждом 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;

1 Ответ

2 голосов
/ 07 октября 2010

Изначально я пытался создать VIEW с этими UNION, но это не сработало из-за различий в логике в каждом UNION и разных требований к параметрам, поэтому я подумал, что функция может решить эту проблему?Если бы я создал функцию, которая принимала за параметр @travellerid, и возвращал список аранжировщиков, основанных на бизнес-правилах, было бы это идеальным / быстрым решением?

Вы думаете, процедурный / OOпрограммирование, но SQL основан на SET.
Функция будет работать, но будет гарантировать, что индекс не может быть использован при использовании функции для критериев принятия решения / и т. д.Нематериализованный вид только немного лучше;в SQL Server есть возможность использовать индексированное представление (материализованное представление AKA), но они общеизвестно ограничены.Он идет вразрез с концепциями модульного программирования, но 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) устранит проблему с дубликатами, возникающую при использовании объединений, если к родительскому элементу подключено более одной дочерней записи.

...