2010-12-06 2 views
1

Я ищу оптимизацию конкатенации по нескольким строкам, и, прочитав некоторые подобные вопросы, я знаком с использованием STUFF + XML-пути и т. Д. Однако, когда я применяю их к моему запросу, он обычно истекает при обращении к 9 миллионов строк или около строк у меня естьоптимальная конкатенация по строкам

Что я ищу это более эффективный способ перевода этого:

create table #fruit 
(
Contact_id NVARCHAR(50) 
,fruit_type NVARCHAR(50) 
,[2005_orders] int 
,[2006_orders] int 
,[2007_orders] int 
,[2008_orders] int 
,[2009_orders] int 
) 
INSERT INTO #fruit VALUES ('id001','banana',1,3,0,25,4) 
INSERT INTO #fruit VALUES ('id001','apple',0,7,19,1,0) 
INSERT INTO #fruit VALUES ('id001','orange',0,0,0,9,0) 
INSERT INTO #fruit VALUES ('id001','strawberry',1,1,1,1,4) 
INSERT INTO #fruit VALUES ('id001','grapes',0,3,0,0,0) 
INSERT INTO #fruit VALUES ('id001','lemon',1,1,1,0,0) 

в это:

CREATE TABLE #results 
(
contact_id NVARCHAR(255) 
,fruit_type NVARCHAR(50) 
,[2005_orders] int 
,[2006_orders] int 
,[2007_orders] int 
,[2008_orders] int 
,[2009_orders] int 
,combination2005 NVARCHAR(500) 
,combination2006 NVARCHAR(500) 
,combination2007 NVARCHAR(500) 
,combination2008 NVARCHAR(500) 
,combination2009 NVARCHAR(500) 
) 
INSERT INTO #results VALUES ('id001','banana',1,3,0,25,4,'banana + strawberry + lemon','banana + apple + strawberry + grapes + lemon','apple + strawberry + lemon','banana + apple + orange + strawberry','banana + strawberry') 
INSERT INTO #results VALUES ('id001','apple',0,7,19,1,0,'banana + strawberry + lemon','banana + apple + strawberry + grapes + lemon','apple + strawberry + lemon','banana + apple + orange + strawberry','banana + strawberry') 
INSERT INTO #results VALUES ('id001','orange',0,0,0,9,0,'banana + strawberry + lemon','banana + apple + strawberry + grapes + lemon','apple + strawberry + lemon','banana + apple + orange + strawberry','banana + strawberry') 
INSERT INTO #results VALUES ('id001','strawberry',1,1,1,1,4,'banana + strawberry + lemon','banana + apple + strawberry + grapes + lemon','apple + strawberry + lemon','banana + apple + orange + strawberry','banana + strawberry') 
INSERT INTO #results VALUES ('id001','grapes',0,3,0,0,0,'banana + strawberry + lemon','banana + apple + strawberry + grapes + lemon','apple + strawberry + lemon','banana + apple + orange + strawberry','banana + strawberry') 
INSERT INTO #results VALUES ('id001','lemon',1,1,1,0,0,'banana + strawberry + lemon','banana + apple + strawberry + grapes + lemon','apple + strawberry + lemon','banana + apple + orange + strawberry','banana + strawberry') 

Если ключевыми факторами являются то, что я хочу, чтобы строка для каждого типа фруктов за один контакт (так как эта таблица будет использоваться в другом месте) и что мне нужен только плод, чтобы превратить его в тип комбинации, если число больше 0.

это может быть, что это никогда не будет очень эффективным, учитывая количество строк, я имею дело с, но если есть какой-то шанс я могу добавить эту информацию на моем столе, что было бы здорово :)

Методы пытались

Метод 1)

SELECT * 
,STUFF(
(SELECT ' ' + fruit_type 
FROM #fruit fr2 
WHERE fr.contact_id = fr2.contact_id 
AND 2005_orders > 0 
order by contact_id,fruit_type 
FOR XML path ('') 
) 
,1,1,'' 
) AS combination 
FROM #fruit fr 

Метод 2)

SELECT * 
,ISNULL((MAX(CASE WHEN fruit_type = 'banana' AND 2005_orders > 0 THEN 'banana ' END) OVER (PARTITION BY contact_id)),'')+ 
ISNULL((MAX(CASE WHEN fruit_type = 'apple' AND 2005_orders > 0 THEN 'apple ' END) OVER (PARTITION BY contact_id)),'')+ 
ISNULL((MAX(CASE WHEN fruit_type = 'orange' AND 2005_orders > 0 THEN 'orange' END) OVER (PARTITION BY contact_id)),'')+ 
ISNULL((MAX(CASE WHEN fruit_type = 'strawberry' AND 2005_orders > 0 THEN 'strawberry ' END) OVER (PARTITION BY contact_id)),'')+ 
ISNULL((MAX(CASE WHEN fruit_type = 'grapes' AND 2005_orders > 0 THEN 'grapes ' END) OVER (PARTITION BY contact_id)),'')+ 
ISNULL((MAX(CASE WHEN fruit_type = 'lemon' AND 2005_orders > 0 THEN 'lemon ' END) OVER (PARTITION BY contact_id)),'')+ 
AS combination05 
FROM #fruit fr 

- который затем повторяется в течение многих лет 2006-2009 (который я знаю, это чудовищно неэффективная)

+0

Что вы уже пробовали? Какой период ожидания? – 2010-12-06 13:06:48

+0

@Ed: Включенные методы: тайм-аут составляет около 2 часов (насколько мне известно) – Dibstar 2010-12-06 13:16:10

+0

Является ли это таблицей отчетов, созданной из других нормализованных данных? – kevpie 2010-12-06 13:17:50

ответ

1

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

Вам не нужно использовать внешние соединения, если у вас есть записи для каждой комбинации contact_id/fruit_type.

Индекс на contact_id должен значительно улучшить производительность.

SELECT 
f.* 
, combination2005 = 
    CASE WHEN b.[2005_orders] = 0 OR b.[2005_orders] IS NULL THEN '' ELSE 'banana + ' END 
    + CASE WHEN a.[2005_orders] = 0 OR a.[2005_orders] IS NULL THEN '' ELSE 'apple + ' END 
    + CASE WHEN o.[2005_orders] = 0 OR o.[2005_orders] IS NULL THEN '' ELSE 'orange + ' END 
    + CASE WHEN s.[2005_orders] = 0 OR s.[2005_orders] IS NULL THEN '' ELSE 'strawberry + ' END 
    , combination2006 = 
    CASE WHEN b.[2006_orders] = 0 OR b.[2006_orders] IS NULL THEN '' ELSE 'banana + ' END 
    + CASE WHEN a.[2006_orders] = 0 OR a.[2006_orders] IS NULL THEN '' ELSE 'apple + ' END 
    + CASE WHEN o.[2006_orders] = 0 OR o.[2006_orders] IS NULL THEN '' ELSE 'orange + ' END 
    + CASE WHEN s.[2006_orders] = 0 OR s.[2006_orders] IS NULL THEN '' ELSE 'strawberry + ' END 
FROM 
#fruit f 
LEFT OUTER JOIN 
(SELECT * FROM #fruit WHERE fruit_type = 'banana') b 
ON 
    f.contact_id = b.contact_id 
LEFT OUTER JOIN 
(SELECT * FROM #fruit WHERE fruit_type = 'apple') a 
ON 
    f.contact_id = a.contact_id 
LEFT OUTER JOIN 
(SELECT * FROM #fruit WHERE fruit_type = 'orange') o 
ON 
    f.contact_id = o.contact_id 
LEFT OUTER JOIN 
(SELECT * FROM #fruit WHERE fruit_type = 'strawberry') s 
ON 
    f.contact_id = s.contact_id 

и не использовать «SELECT *», я просто ленив.

Я должен добавить, что если вы не ожидаете, что каждый contact_id имеет запись для каждого файла fruit_type (таким образом, вам нужно использовать внешние соединения здесь), тогда выражения case также должны проверять значение null в дополнение к нулю. (Добавлено, что выше)

0

Это не может быть целесообразным/возможно в вашей среде, но! учитывая, что эти цифры относятся к прошлому, считали ли вы предварительным генерированием конкатенированной строки на контакт в год в таблицу, используя любой метод, который у вас есть в настоящее время, и присоединяете его к вашим результатам?

Возможно, вам придется использовать запланированное задание для поддержания строки в текущем году, но маловероятно, что данные за 2005-9 год будут изменены.

0

Я считаю, что тайм-аут можно проследить до количества избыточных данных, которые вы вычисляете. Когда я посмотрел ваши образцы, кажется, что список фруктов рассчитывается для каждой строки таблицы. Я использую другой подход, который может помочь.

Я использовал выбранный ниже, чтобы поместить имя фрукта вместо значения продаж.

SELECT 
contact_id 
,substring([fruit_type],1,cast(CAST([2005_orders] as bit)as int)*50) AS [2005_fruit] 
,substring([fruit_type],1,cast(CAST([2006_orders] as bit)as int)*50) AS [2006_fruit] 
,substring([fruit_type],1,cast(CAST([2007_orders] as bit)as int)*50) AS [2007_fruit] 
,substring([fruit_type],1,cast(CAST([2008_orders] as bit)as int)*50) AS [2008_fruit] 
,substring([fruit_type],1,cast(CAST([2009_orders] as bit)as int)*50) AS [2009_fruit] 
from #fruit 

contact_id           2005_fruit           2006_fruit           2007_fruit           2008_fruit           2009_fruit 
-------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- 
id001            banana            banana                        banana            banana 
id001                         apple            apple            apple            
id001                                                  orange            
id001            strawberry           strawberry           strawberry           strawberry           strawberry 
id001                         grapes                                     
id001            lemon            lemon            lemon                         

Я считаю, что следующим шагом является поворот выходного сигнала выбранного показанного объединения фруктов. Цель должна быть таблицей, которая может быть соединена с исходным таблицей фруктов. При необходимости таблица может быть упрочнена в таблице результатов, за исключением того, что существует много избыточных данных, которые убьют вас IO.

Смежные вопросы