优化 SQL- 将函数换成 JOINS 并在变量存在时混淆

Optimizing SQL- swapping out functions for JOINS and confusion when variables exist

我刚开始在一家出版公司从事 Dev Ops 的新工作。我的第一个任务是优化一个由函数组成的巨大 SQL 查询。功能真的很慢。创建查询的人很聪明,但不知道 SQL 并且在他本可以使用 JOIN 的时候使用了函数。我在转换具有变量的函数时遇到问题。例如,这是功能之一。这是在查询中,接下来是存储在别处的关联函数。

dbo.rpt_get_isbn(b.bookkey, 21) AS 
f_upc

然后函数...

ALTER FUNCTION [dbo].[rpt_get_isbn](
        @i_bookkey  INT,
        @i_isbn_type    INT)

/*  Returns the identifier such as EAN, 
ISBN, with or without dashes


   PARAMETER @i_isbn_type
        10 = ISBN10
        13 = ISBN 13
        16 = EAN
        17 = EAN (no dashes)
        18 = GTIN
        19 = GTIN (no dashes)
        20 = LCCN
        21 = UPC
*/
    RETURNS VARCHAR(50)

AS
BEGIN
        DECLARE @RETURN VARCHAR(50)
        DECLARE @v_desc VARCHAR(50)

    IF @i_isbn_type = 10
        BEGIN
            SELECT @v_desc = isbn10
            FROM isbn
            WHERE bookkey = @i_bookkey
        END

    ELSE IF @i_isbn_type = 13
        BEGIN
            SELECT @v_desc = isbn
            FROM isbn
            WHERE bookkey = @i_bookkey
        END

    ELSE IF @i_isbn_type = 16
        BEGIN
           SELECT @v_desc = ean
           FROM isbn
            WHERE bookkey = @i_bookkey
        END
    ELSE IF @i_isbn_type = 17
        BEGIN
            SELECT @v_desc = ean13
            FROM isbn
            WHERE bookkey = @i_bookkey
        END
    ELSE IF @i_isbn_type = 18
        BEGIN
            SELECT @v_desc = gtin
            FROM isbn
            WHERE bookkey = @i_bookkey
        END
    ELSE IF @i_isbn_type = 19
        BEGIN
            SELECT @v_desc = gtin14
            FROM isbn
            WHERE bookkey = @i_bookkey
        END
    ELSE IF @i_isbn_type = 20
        BEGIN
            SELECT @v_desc = lccn
            FROM isbn
            WHERE bookkey = @i_bookkey
        END
    ELSE IF @i_isbn_type = 21
        BEGIN
            SELECT @v_desc = upc
            FROM isbn
            WHERE bookkey = @i_bookkey
        END
    IF LEN(@v_desc) > 0
        BEGIN
            SELECT @RETURN = 
LTRIM(RTRIM(@v_desc))
        END
    ELSE
        BEGIN
            SELECT @RETURN = ''
        END

  RETURN @RETURN
END

所以这个函数可以return基于作为第二个参数给出的变量的各种不同的结果。如果那不存在,这将很容易。我会简单地用像这样的解决方案来转换它来检索这本书的封面..

LTRIM(RTRIM(bo.ean13)) AS p_coverimagepath

并且需要 JOIN...

LEFT JOIN Isbn bo WITH (NOLOCK) ON bo.bookkey = b.bookkey

但同样,现在我正在处理参数和使用 If/elses 得出答案的函数。那么我是否需要将此 if/else 逻辑添加到我的主查询中?我想不出一种方法可以产生如此简单的答案。我期待着弄清楚这一点。如果我忘记了理解我在做什么的任何关键要素,请告诉我。谢谢!

更新 这是代码的去向

,pss8.dbo.xml_StripIllegalChars(dbo.rpt_get_series_volume(b.bookkey)) AS 
p_seriesvol
    ,CASE
        WHEN dbo.rpt_get_isbn(b.bookkey, 17) = ''
            THEN (
                    SELECT ipg_id
                    FROM tmmdb.ipg_extra.dbo.vw_Pss8IsbnOrUpc bo
                    WHERE bo.bookkey = b.bookkey
                    )
        ELSE dbo.rpt_get_isbn(b.bookkey, 17)
        END AS p_coverimagepath
    ,CASE
        WHEN dbo.rpt_get_isbn(b.bookkey, 17) = ''
            THEN (
                    SELECT ipg_id
                    FROM tmmdb.ipg_extra.dbo.vw_Pss8IsbnOrUpc bo
                    WHERE bo.bookkey = b.bookkey
                    )
        ELSE dbo.rpt_get_isbn(b.bookkey, 17)
        END AS TSP_p_coverimagepath
    ,pss8.dbo.xml_StripIllegalChars(replace(dbo.rpt_get_title(b.bookkey, 
'T'), '&', '&')) AS p_title /*  30OCT14 */
    
,pss8.dbo.xml_StripIllegalChars(replace(dbo.rpt_get_sub_title(b.bookkey), 
'&', '&')) AS p_subtitle /* 20OCT14 */

这不是一个完整的答案,而是一个示例结构,可以帮助您解决这个问题。我做了很多假设,因为你的问题需要更多细节。但希望您能体会到这样更简单。

SELECT 
CASE 
    WHEN ISNULL(LTRIM(RTRIM(bo.ean13)),'') = '' THEN T2.ipg_id 
    ELSE LTRIM(RTRIM(bo.ean13))
END as p_coverimagepath
FROM MainTable b
LEFT JOIN Isbn bo 
ON bo.bookkey = b.bookkey
LEFT JOIN tmmdb.ipg_extra.dbo.vw_Pss8IsbnOrUpc T2
ON T2.bookkey=b.bookkey

在您的示例代码中,两列的作用完全相同,因此我没有重复这一点。

注意几点:

-不要在你的代码中加入 NOLOCK,认为这是一种性能提升

-如果您使用外部联接,则需要进行调整以防返回 NULL

-加入 tmmdb.ipg_extra.dbo.vw_Pss8IsbnOrUpc 并使用其中的列比一遍又一遍地重复代码更容易。