bee*_*eks 20 performance sql-server sql-server-2008-r2 view functions query-performance
在分析数据库时,我遇到了一个视图,该视图引用了一些非确定性函数,对于此应用程序池中的每个连接,这些函数每分钟被访问1000-2500 次。一个简单的视图产生以下执行计划:SELECT
对于少于一千行且每隔几个月可能会看到一两行更改的视图来说,这似乎是一个复杂的计划。但以下其他注意事项会变得更糟:
UDF
s 来构建字符串UDF
s 以获取本地化语言的 ISO 代码UDF
作为JOIN
谓词INSERT
/ UPDATE
/DELETE
在每个触发器来写入底层表CURSORS
该EXEC
存储过程作为参考更多的这些串建设UDF
秒。这对我来说似乎很糟糕,但我只有几年的 TSQL 经验。也越来越好!
看来开发人员认为这是一个好主意,这样做是为了让存储的几百个字符串可以根据从UDF
特定于模式的a 返回的字符串进行翻译。
这是堆栈中的一个视图,但它们都同样糟糕:
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
,CASE
WHEN ISNULL(il.I18NID, N'') = N''
THEN id.IETFLangCode
ELSE il.IETFLangCode
END AS IETFLangCode
,dbo.User3StringI18N_KeyValue(b.WKType, b.WKIndex, 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, b.WKIndex, N'WKS')
AND il.IETFLangCode = dbo.UserI18N_Session_Locale_Key()
)
LEFT OUTER JOIN User3StringI18N id
ON (
id.I18NID = dbo.User3StringI18N_KeyValue(b.WKType, b.WKIndex,N'WKS')
AND id.IETFLangCode = dbo.UserI18N_Database_Locale_Key()
)
GO
Run Code Online (Sandbox Code Playgroud)
这就是为什么UDF
s 被用作JOIN
谓词的原因。该I18NID
列通过连接形成:STRING + [ + ID + | + ID + ]
在测试这些时,SELECT
视图中的一个简单返回 ~309 行,执行时间为 900-1400 毫秒。如果我将字符串转储到另一个表中并在其上建立索引,则相同的选择会在 20-75 毫秒内返回。
所以,长话短说(我希望你能理解其中的一些愚蠢)我想成为一个好心人,为 99% 的运行这个产品的客户重新设计和重写这个,他们根本不使用任何本地化 - -[en-US]
即使英语是第二/第三语言,最终用户也应该使用语言环境。
由于这是一个非官方的黑客攻击,我在考虑以下几点:
NVARCHAR
和INT
列的WKType
和WKIndex
列。UDF
引用这些视图的s 以避免在某些连接谓词中进行类型转换(我们最大的审计表是 500-2,000M 行,并将 an 存储INT
在NVARCHAR(4000)
用于连接WKIndex
列 ( INT
)的列中。)现在,我的实际问题:
UDF
作为存根有哪些替代方案?(我可以VIEW
为每个架构所有者编写一个特定的代码,并对语言进行硬编码,而不是依赖于各种UDF
存根。)UDF
s 然后模式绑定视图堆栈来简单地使这些视图具有确定性?看看给定的代码,我们可以说,
其次,不应为同一列频繁调用 UDF。这里,它在 select 中被调用一次
,dbo.User3StringI18N_KeyValue(b.WKType, b.WKIndex, N'WKS') AS I18NID
Run Code Online (Sandbox Code Playgroud)
以及第二次加入
.IETFLangCode = dbo.User3StringI18N_KeyValue(b.WKType, b.WKIndex, N'WKS')
Run Code Online (Sandbox Code Playgroud)可以在临时表中生成值,或者使用 CTE(通用表表达式)在连接发生之前首先获取这些值。
我生成了一个示例 USP,它将提供一些改进:
CREATE PROCEDURE usp_UserWKStringI18N
AS
BEGIN
-- Do operation using UDF
SELECT b.WKType
,b.WKIndex
,dbo.User3StringI18N_KeyValue(b.WKType, b.WKIndex, N'WKS') AS I18NID
,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
,b.WKIndex
,CASE
WHEN ISNULL(il.I18NID, N'') = N''
THEN id.I18NString
ELSE il.I18nString
END AS WKString
,CASE
WHEN ISNULL(il.I18NID, 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
Run Code Online (Sandbox Code Playgroud)
请尝试这个
归档时间: |
|
查看次数: |
1037 次 |
最近记录: |