Попытка локализации базы данных с использованием табличных функций

Я ищу мнения о следующей технике локализации:

Начнем с 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 

Мне интересно, есть ли серьезные проблемы с производительностью вокруг этого или каких-либо демонстраторов. Какие-то причины, по которым я не должен принять это?

Изменить: я отметил этот 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? View делает то же самое?

7.11.2009 16:55:09
SQL Server? Можете ли вы поменять с версией (2000 против 2005 против 2008)? То, как обрабатываются UDF, существенно отличается в разных версиях SQL.
Kevin Crumley 7.11.2009 17:15:00
@Radu: используйте представление вместо функции. Ваша функция работает как SUBSELECT - в этом нет необходимости, и в зависимости от использования в будущем вам может потребоваться другая связанная информация.
OMG Ponies 7.11.2009 17:38:13
Насколько я понимаю, я не могу передать параметры представлениям, не так ли?
Radu094 7.11.2009 17:41:20
@Radu: Вы определяете WHEREкритерии фильтра для представлений. Ваш подход к параметрам не является масштабируемым и может привести к снижению производительности в зависимости от использования. SQL установлен на основе, а не процедурный ...
OMG Ponies 7.11.2009 18:19:33
3 ОТВЕТА

Можно поспорить, что вам придется переводить больше, чем названия продуктов. Поэтому я бы разработал решение для перевода, чтобы обрабатывать любые виды строк.

Например, вы можете иметь таблицу локализации, например:

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'

PS Для настоящей программы я бы использовал более краткое описание, чем TranslatableStringId, например tsid, потому что переводы появляются везде.

0
7.11.2009 17:19:30
Пожалуйста, не используйте сокращение для имени столбца - нет ничего хуже, чем выяснять, что кто-то использует сокращение, когда символов более чем достаточно для поддержки удобочитаемого, информативного имени столбца. Особенно в ORM, где у вас меньше шансов использовать ссылочную целостность.
OMG Ponies 7.11.2009 17:43:47
Вам нужен TranslatableStringIdстолбец - разве это не Idстолбец? Просто странно, что Idвыглядит как ПК, но вы не ссылаетесь на это. Я бы назвал это более очевидным: TRANSLATION_IDили LOCALIZATION_ID...
OMG Ponies 7.11.2009 17:46:55
Один idидентифицирует строку на одном языке. TranslatableStringIdОпределяет несколько переводов одного и того же строки.
Andomar 7.11.2009 17:52:15
Так как же вы гарантируете, что 123 всегда ассоциируется с «en-US»?
OMG Ponies 7.11.2009 18:20:59
Переводчик должен убедиться, что 123 переведен для каждой поддерживаемой локали. Вы можете написать запрос, чтобы убедиться в этом
Andomar 7.11.2009 18:30:54

Краткий ответ: Как правило, нет ничего плохого в использовании TVF для такого рода вещей, но я бы предложил сделать идентификатор также параметром:

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 имеет тенденцию обрабатывать пользовательские функции более процедурным, чем декларативным образом, поэтому он не интерпретирует то, что вам нужно, а затем находит лучший способ получить то, что вам нужно. хочу, но на самом деле выполняет в порядке инструкции, которые вы написали. Так что мне кажется, что этот метод будет:

  1. выделите весь англоязычный текст, поместив его в табличную переменную.
  2. возьмите результаты шага # 1 и выберите любые записи с заданным идентификатором.

Это будет означать большое количество потраченных впустую циклов, в результате чего в табличную переменную помещается в основном неиспользованный текст на английском языке, прежде чем применять фильтр идентификаторов к этому набору результатов. С другой стороны, размещение всех фильтров в UDF позволило бы SQL Server определить, проще ли сначала фильтровать по идентификатору (более вероятно, при условии стандартной схемы индексации), а затем применить фильтр языковых стандартов или наоборот. В любом случае, вы должны иметь меньше данных, перемещаемых в фоновом режиме, и, следовательно, иметь лучшую производительность, если вы поместите все свои фильтры в одном месте. Опять же, все это предполагает, что SQL Server не делает гигантских скачков в оптимизации. Но если так, это еще одна причина сказать, да, нет проблем с использованием TVF.

1
7.11.2009 17:39:59
Как бы это повлияло на список товаров?
Andomar 7.11.2009 17:34:59
РЕШЕНИЕ

Я хотел вернуться с ответом на этот вопрос после гораздо большего тестирования. Мне кажется, что 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 задействовано в два раза больше таблиц, чем в обычных запросы.

0
12.11.2009 19:27:18