我正在寻找以下本地化技术的意见:
我们从2个表开始:
tblProducts : ProductID, Name,Description,SomeAttribute
tblProductsLocalization : ProductID,Language,Name,Description
和表值函数:
CREATE FUNCTION [dbo].[LocalizedProducts](@locale nvarchar(50))
RETURNS TABLE
AS (SELECT a.ProductID,COALESCE(b.Name,a.Name)as [Name],COALESCE(b.Description,a.Description)as [Description],a.SomeAttribute
from tblProducts a
left outer join tblProductsLocalization_Locale b
on a.ProductID= b.ProductID and b.[Language]=@locale)
我打算做的是每当我需要返回本地化数据时都包含该函数:
select * from LocalizedProducts('en-US') where ID=1
而不是
select * from tblProducts where ID=1
如果这个或任何showstoppers存在重大的性能问题,我很感兴趣。我不应该采用这个理由吗?
编辑:我已经标记了这个SQL2005,尽管我使用2008开发它,我认为部署目标只有SQL2005。如果有需要,我可以升级到2008年。
稍后编辑:
我创建了一个视图,内容相同但没有参数:
CREATE VIEW [dbo].[LocalizedProductsView]
AS
SELECT b.Language,a.ProductID,COALESCE(b.Name,a.Name)as [Name],
COALESCE(b.Description,a.Description)as [Description],a.SomeAttributefrom tblProducts a
left outer join tblProductsLocalization_Locale b on a.ProductID= b.ProductID
然后我继续进行一些测试: 估计的执行计划看起来与两个查询完全相同:
select * from LocalizedProducts('us-US') where SomeNonIndexedParameter=2
select * from LocalizedProductsView where (Language='us-US' or Language is null) and SomeNonIndexedPramaters=2
最终提出的问题:我是否应该了解TVF正在计算所有产品的翻译,无论WHERE参数如何?是在做同样的事情吗?
答案 0 :(得分:1)
简短回答:作为一般规则,使用TVF进行此类操作没有任何问题,但我建议将ID作为参数:
CREATE FUNCTION [dbo].[LocalizedProducts](@ID int, @locale nvarchar(50))
RETURNS TABLE
AS (SELECT a.ProductID,COALESCE(b.Name,a.Name)as [Name],COALESCE(b.Description,a.Description)as [Description],a.SomeAttribute
from tblProducts a
left outer join tblProductsLocalization _Locale b
on a.ProductID= b.ProductID and b.[Language]=@locale)
where a.ProductId = @ID
像这样使用:
select * from LocalizedProducts(1, 'en-US')
更长的解释: 我在SQL 2008中从未尝试过类似的东西,所以SQL Server可能会优化这个问题。
但是,我在早期版本中的经验似乎表明SQL Server倾向于处理 用户定义的函数采用更多的过程而非声明的方式,因此它不会解释您想要的内容,然后找出最适合您的方式,但实际上是按照您编写的指令执行的。所以在我看来,这种方法会:这将意味着大量浪费的周期,在将ID过滤器应用于该结果集之前,将大部分未使用的英文文本放入表变量中。另一方面,将所有过滤器放入UDF将让SQL Server确定是否最容易按ID过滤(更可能是假设采用标准索引方案),然后应用区域设置过滤器,反之亦然。无论哪种方式,如果您将所有过滤器放在一个位置,那么您应该在后台移动较少的数据,从而获得更好的性能。同样,这一切都假设SQL Server现在没有在优化方面实现巨大飞跃。但如果是这样,那就更有理由说,是的,使用TVF没有问题。
答案 1 :(得分:0)
可以肯定的是,您必须翻译的不仅仅是产品名称。所以我设计了翻译解决方案来处理任何类型的字符串。
例如,您可以使用如下的本地化表:
Id, TranslatableStringId, Language, Translation
然后每个产品都可以有一个可翻译的字符串。但也是产品清单顶部的解释性文字。
对于产品,您可以查询:
SELECT *
FROM Products p
INNER JOIN Translations t
ON p.DescriptionId = t.TranslatableStringId
AND t.language = 'en-US'
对于解释性文字,你会得到一个简单的:
SELECT t.Translation
FROM Translations t
WHERE t.TranslatableStringId = 123 -- ID of string
AND t.language = 'en-US'
P.S。对于一个真正的程序,我会使用比TranslatableStringId更简短的描述,比如tsid
,因为翻译往往会随处可见。
答案 2 :(得分:0)
我想在做了更多测试之后再回答这个问题。 在我看来,在执行查询计划并相应地进行优化时,SQL2008实际上正在查看TVF:
例如:
select pr.* from LocalizedProducts('en-US') pr inner join LocalizedPhotos('en-US') ph on
ph.ProductId=pr.Id where pr.SomeUnindexProperty= 5
此查询需要触及4个表:
Products
Products_Localization
Photos
Photos_Localization
查询计划的外观是(让我看看我是否可以格式化):
Product gets a Clustered Index Seek
-- >> Products gets nested loop with Photos
-->> nested loop Products_Localization -
->> nested loop Photos_Localization.
如果TVF是黑匣子,那么这不是你所期望的。 Product得到索引的简单事实SEEK会告诉我该查询不会盲目地解释整个TVF。
我进行了大量的性能测试,平均而言,“本地化”TVF比使用直接表查询慢50%-100%,但这可能是因为TVF中涉及的表多于两倍。在正常的查询中。