优化 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
并使用其中的列比一遍又一遍地重复代码更容易。
我刚开始在一家出版公司从事 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
并使用其中的列比一遍又一遍地重复代码更容易。