sql-server – SQL Server – 处理嵌套的非确定性视图堆栈中字符串的本地化

前端之家收集整理的这篇文章主要介绍了sql-server – SQL Server – 处理嵌套的非确定性视图堆栈中字符串的本地化前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
在分析数据库时,我遇到了一个视图,该视图引用了一些非确定性函数,每个连接在此应用程序池中每分钟访问1000-2500次.视图中的简单SELECT产生以下执行计划:




这似乎是一个复杂的计划,一个不到一千行的视图,每隔几个月就会看到一行或两行.但随着以下其他纪念活动,情况会变得更糟:

>嵌套视图是非确定性的,因此我们无法对它们编制索引
>每个视图引用多个UDF来构建字符串
>每个UDF都包含嵌套的UDF,以获取本地化语言的ISO代码
>堆栈中的视图使用从UDF返回的其他字符串构建器作为JOIN谓词
>每个视图堆栈都被视为一个表,这意味着每个视图堆栈都有INSERT / UPDATE / DELETE触发器写入基础表
>视图上的这些触发器使用CURSORS EXEC存储过程,这些过程引用了更多这些字符串构建UDF.

这对我来说似乎很糟糕,但我只有几年的Tsql经验.它也变得更好!

看起来开发人员认为这是一个好主意,做了所有这些,以便存储的几百个字符串可以基于从特定于模式的UDF返回的字符串进行转换.

这是堆栈中的一个视图,但它们都同样糟糕:

CREATE VIEW [UserWKStringI18N]
AS
SELECT b.WKType,b.WKIndex,CASE
       WHEN ISNULL(il.I18NID,N'') = N''
       THEN id.I18NString
       ELSE il.I18nString
       END AS WKString,N'') = N''
       THEN id.IETFLangCode
       ELSE il.IETFLangCode
       END AS IETFLangCode,dbo.User3StringI18N_KeyValue(b.WKType,N'WKS') AS I18NID,dbo.UserI18N_Session_Locale_Key()  AS IETFSessionLangCode,dbo.UserI18N_Database_Locale_Key() AS IETFDatabaseLangCode
FROM   UserWKStringBASE b
LEFT OUTER JOIN User3StringI18N il
ON    (
il.I18NID       = dbo.User3StringI18N_KeyValue(b.WKType,N'WKS')
AND il.IETFLangCode = dbo.UserI18N_Session_Locale_Key()
)
LEFT OUTER JOIN User3StringI18N id
ON    (
id.I18NID       = dbo.User3StringI18N_KeyValue(b.WKType,N'WKS')
AND id.IETFLangCode = dbo.UserI18N_Database_Locale_Key()
)
GO

这就是为什么UDF被用作JOIN谓词的原因. I18NID列通过连接:STRING [ID | ID ]

在测试这些过程中,视图中的一个简单的SELECT返回~309行,并执行900-1400ms.如果我将字符串转储到另一个表中并在其上打一个索引,则相同的select将在20-75ms内返回.

所以,长话短说(我希望你对这种愚蠢行为表示赞赏)我希望成为一名优秀的撒玛利亚人,并为99%运行该产品的客户重新设计并重新编写此内容,而这些客户并未使用任何本地化 – 即使英语是第二/第三语言,即使用户也应使用[en-US]语言环境.

由于这是一个非正式的黑客攻击,我想到的是:

>创建一个新的String表,其中填充了原始基表中干净连接的数据集
>索引表格.
>在堆栈中创建一组替换的顶级视图,其中包括WKType和WKIndex列的NVARCHAR和INT列.
>修改引用这些视图的少数UDF,以避免某些连接谓词中的类型转换(我们最大的审计表是500-2,000M行,并在NVARCHAR(4000)列中存储INT,用于连接WKIndex列( INT).)
> Schemabind的观点
>向视图添加一些索引
>使用set logic而不是游标在视图上重建触发器

现在,我的实际问题:

>是否有通过视图处理本地化字符串的最佳实践方法
>使用UDF作为存根有哪些替代方案? (我可以为每个架构所有者编写一个特定的VIEW并对该语言进行硬编码,而不是依赖于各种UDF存根.)
>通过完全限定嵌套UDF然后对视图堆栈进行模式绑定,可以简单地使这些视图成为确定性的吗?

解决方法

看一下给定的代码,我们可以说,

>首先,这不应该是一个视图,但它应该是一个存储过程,因为它不仅仅是从表中读取,而是使用UDF.
>其次,不应经常为同一列调用UDF.在这里,它在select中被调用一次

,N'WKS') AS I18NID

第二次加入

.IETFLangCode = dbo.User3StringI18N_KeyValue(b.WKType,N'WKS')

可以在临时表中生成值或使用CTE(公用表表达式)在连接发生之前首先获取这些值.

我已经生成了一个样本USP,它将提供一些改进:

CREATE PROCEDURE usp_UserWKStringI18N
AS
BEGIN
    -- Do operation using UDF 
    SELECT b.WKType,dbo.UserI18N_Session_Locale_Key() AS IETFSessionLangCode,dbo.UserI18N_Database_Locale_Key() AS IETFDatabaseLangCode
    INTO #tempTable
    FROM UserWKStringBASE b;

    -- Now final Select
    SELECT b.WKType,CASE 
            WHEN ISNULL(il.I18NID,N'') = N''
                THEN id.I18NString
            ELSE il.I18nString
            END AS WKString,N'') = N''
                THEN id.IETFLangCode
            ELSE il.IETFLangCode
            END AS IETFLangCode,b.I18NID,b.IETFSessionLangCode,b.IETFDatabaseLangCode
    FROM #tempTable b
    LEFT OUTER JOIN User3StringI18N il
        ON il.I18NID = b.I18NID
            AND il.IETFLangCode = b.IETFSessionLangCode
    LEFT OUTER JOIN User3StringI18N id
        ON id.I18NID = b.I18NID
            AND id.IETFLangCode = b.IETFDatabaseLangCode
END

请试试这个

猜你在找的MsSQL相关文章