2015-12-11 3 views
2

Возможно ли построить функции типа поиска в SQL Server или они всегда уступают (производительности) просто писать подзапросы/объединения?Функции поиска SQL Server

Я хотел бы взять некоторый код, как этого

SELECT 
    ContactId, 
    ProductType, 
    SUM(OrderAmount) TotalOrders 
FROM 
    (
     SELECT 
      ContactId, 
      ProductType, 
      OrderAmount 
     FROM 
      UserOrders ord 
      JOIN 
      (
       SELECT 
        ProductCode, 
        CASE 
         --Complex business logic 
        END ProductType 
       FROM 
        ItemTable 
      ) item 
      ON 
       item.ProductCode=ord.ProductCode 

    ) a 
GROUP BY 
    ContactId, 
    ProductType 

И вместо того, чтобы иметь возможность написать запрос, как этого

SELECT 
    ContactId, 
    UDF_GET_PRODUCT(ProductCode) ProductType, 
    SUM(OrderAmount) TotalOrders 
FROM 
    UserOrders 
GROUP BY 
    ContactId, 
    UDF_GET_PRODUCT(ProductCode) 

ответ

1

Возможно, но не совсем в том формате, который вы описали. Является ли это целесообразным или не совсем зависит.

Я согласен с другим ответом в том, что скалярные функции являются убийцами производительности, и я лично их вообще не использую. Это, как говорится, я не думаю, что это причина игнорировать принцип СУХОЙ, где это возможно. т. е. я бы не стал сокращать , если это повлияло на производительность, однако мне также не нравится идея повторной сложной логики в нескольких местах. Когда что-то меняется, у вас есть несколько запросов, которые необходимо изменить, и неизбежно некоторые пропущены, поэтому, если вы будете повторно использовать эту логику , то это хорошая идея, чтобы инкапсулировать ее в одном месте.

Основываясь на вашем примере, возможно, взгляд был бы наиболее подходящим:

CREATE VIEW dbo.ItemTableWithLogic 
AS 
    SELECT ProductCode, 
      ProductType = <your logic> 
    FROM ItemTable; 

Тогда вы можете просто использовать:

SELECT ord.ContactId, item.ProductType, SUM(ord.OrderAmount) AS TotalOrders 
FROM UserOrders AS ord 
     INNER JOIN dbo.ItemTableWithLogic AS item 
      ON item.ProductCode=ord.ProductCode 
GROUP BY ord.ContactId, item.ProductType; 

что упрощает вещи немного.

Другой альтернативой является встроенный стол функция, что-то вроде:

CREATE FUNCTION dbo.GetProductType (@ProductCode INT) 
RETURNS TABLE 
AS 
RETURN 
( SELECT ProductType = <your logic> 
    FROM ItemTable 
    WHERE ProductCode = @ProductCode 
); 

Что можно вызвать с помощью:

SELECT ord.ContactId, item.ProductType, SUM(ord.OrderAmount) AS TotalOrders 
FROM UserOrders AS ord 
     CROSS APPLY dbo.ItemTableWithLogic(ord.ProductCode) AS item 
GROUP BY ord.ContactId, item.ProductType; 

Мое предпочтение для представлений над столом значных функций, однако, было бы действительно зависит от вашего использования, о котором я бы рекомендовал, поэтому я действительно не хочу выбирать сторону, я буду придерживаться сидения на заборе.

Таким образом, если вам нужно только использовать логику в одном месте и не нужно будет повторно использовать ее во многих запросах, тогда просто придерживайтесь подзапроса. Если вам нужно повторно использовать одну и ту же логику несколько раз, не используйте функцию скалярного значения так же, как вы можете на процедурном языке, но также не позволяйте этому исключать другие способы сохранения вашей логики в одном месте.

1

прилипает к подзапросам и присоединяется.

Поскольку он будет использовать подход на основе набора и выполнить внутренний запрос один раз, примените агрегат к результирующему набору, возвращенному из внутреннего запроса, и верните конечный набор результатов.

С другой стороны, если вы используете функцию Scalar, как показано во втором запросе, весь код внутри функции (подзапрос в исходном вопросе) будет выполнен для каждой возвращаемой строки.

Скалярные функции являются убийцами производительности и должны избегать их, когда это возможно. Это менталитет .net, что если вам нужно снова написать кусок кода и снова поместить его внутри метода и вызвать метод, а не true для сервера sql.

Смежные вопросы