SQL Computed Column用于导致性能问题的查询

时间:2015-03-06 18:38:00

标签: sql sql-server

我有一个包含A,B,C列的表和另一个包含列用户名的表。

在C栏中,我有一个函数getName(A)。

getName(A)大致是

CREATE FUNCTION [dbo].[GetName] (
    @name VARCHAR(100)
    )
RETURNS VARCHAR(100)
WITH SCHEMABINDING
AS
BEGIN
    DECLARE @retval VARCHAR(100);
    DECLARE @nextWord VARCHAR(100);
    SET @retval = @name

    IF EXISTS (Select 1 from someTable where username = SUSER_NAME())
    BEGIN
    SET @name = Replace(Replace(Replace(RTRIM(LTRIM(@name)),',',' ,'),'(','( '),')',' )')
    SET @retval = LEFT(@name, 1);
        WHILE CHARINDEX(' ', @name, 1) > 0
        BEGIN
            SET @name = LTRIM(RIGHT(@name, LEN(@name) - CHARINDEX(' ', @name, 1)));

            IF CHARINDEX(' ', @name, 1) > 0
            BEGIN
                SET @nextWord = LTRIM(LEFT(@name, CHARINDEX(' ', @name, 1) - 1))
            END
            ELSE
            BEGIN
                SET @nextWord = @name
            END

            SET @retval += ' ' + CASE 
                    WHEN @nextWord IN (
                            'List'
                            ,'Of'
                            ,'Different'
                            ,'Words'
                            )
                        THEN @nextWord
                    WHEN ISNUMERIC(@nextWord) = 1
                        THEN @nextWord
                    WHEN ISDATE(@nextWord) = 1
                        THEN @nextWord
                    ELSE LEFT(@nextWord, 1)
                    END
        END
    END

    RETURN @retval;
END

现在,当我尝试在查询中使用C列时,它基本上超时了。试图弄清楚是否有办法让它更快。如果C的计算函数只是引用A,则它运行正常。但当它选择A或选择A中每个单词的第一个字母以及允许列表中的单词时,它会变慢。如果我将此功能设为true,则它会相对较快。我尝试了存在但仍然不快。

非常感谢任何建议。

编辑:我更新了上面的功能。我应该注意,当EXISTS查询返回True时它会快速运行,当它返回false时它运行缓慢。这是我感到困惑的更大困境。

1 个答案:

答案 0 :(得分:2)

这是一个非常合理的函数,因为它是创建引用另一个表的计算列的唯一方法。

以下代码更安全:

BEGIN

    DECLARE @retval VARCHAR(100);

    IF EXISTS (SELECT 1 FROM someTable WHERE username = SUSER_NAME)
    BEGIN
        SET @retval = LEFT(@name, 1);
    END
    ELSE SET @retval = @name;
    RETURN @retval;
END

isnull()方法很聪明,但如果表中有多行与where条件匹配,则原始代码会生成错误。此外,它需要考虑表中的所有值,而不仅仅是第一个。 EXISTS知道停在第一个匹配的行。

您需要sometable(username)上的索引。您可以通过创建唯一约束或通过显式创建索引来执行此操作。