导致性能问题的查询中使用的SQL计算列

导致性能问题的查询中使用的SQL计算列,sql,sql-server,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); S

我有一个包含列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中每个单词的第一个字母以及允许列表中的单词时,它会变慢。如果我总是把这个函数设为真,它会运行得比较快。我试过使用exists,但仍然不快

如有任何建议,将不胜感激


编辑:我更新了上面的函数。我应该注意,当EXISTS查询返回True时,它运行得很快,当它返回false时,它运行得很慢。这是我感到困惑的更大的难题。

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

以下代码更安全:

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
条件匹配,则原始代码将生成错误。此外,它需要考虑表中的所有值,而不仅仅是第一个值<代码>存在知道在第一个匹配行停止


您需要
sometable(username)
上的索引。您可以通过创建唯一约束或显式创建索引来实现这一点。

太可怕了!从不再使用ISNULL方法开始,使用简单的EXISTS可以做得更好。为了真正帮助您避免在选择中使用类似的内联函数。如有必要,创建一个视图并与之连接。还可以查看您的查询中是否没有索引问题。无论如何,如果可以在someTable中找到,则返回
@name
第一个字符,否则返回整个
@name
。看起来很傻,好吧,你到底想干什么?@Kevin。标题很清楚。OP希望用公式创建一个计算列,这个公式虽然很神秘,但必须满足某些局部要求。您不能创建直接引用另一个表的计算列,因此该函数是必需的。@GordonLinoff我想我应该更清楚一些。我认为这可能是XY问题的一个例子。我试图避免它,并找出OP实际需要什么,而不是回答问题。是否可以使用内联函数(而不是多语句)来代替?这可能有助于解决所有问题,尽管在搜索时仍然需要可怕的扫描。@MatBailie不确定是否可以使用内联函数,因为它引用了另一个表。Gordon,我将查询改为Exists而不是ISNULL,但用户名是表中唯一的列,它被设置为PK,因此不应该有重复项,但Exists的优点似乎是它在查找时停止,因为这将在表搜索中继续。不过,这张表中只有几条记录。@Jerry。主键有一个索引,因此
存在
是一个快速索引查找。即使引擎忽略了唯一约束,它也会在下一个值处提前达到峰值,并且只返回一个值。我猜开销在函数本身。我建议您将其作为视图而不是计算列来编写。@GordonLinoff如何将其作为视图来编写?进退两难的是,我们有一个现有的列(columnName)名称,该名称由报告、脚本和许多其他内容引用。我所做的是创建一个名为columnNameActual的列,现在让columnName引用返回columnNameActual或columnNameActual中每个单词的第一个字母的函数。我们有太多引用columnName的内容,以便将它们全部更改为引用视图。所以我想把它改成计算列是可以的,但是性能很差,我想看看如何解决这个问题。@Jerry。我不知道你所说的“在视图中使用它”是什么意思。也许你应该问另一个问题。