powered by simpleCommunicator - 2.0.59     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / Большой UPDATE
48 сообщений из 48, показаны все 2 страниц
Большой UPDATE
    #40026026
Oleg_SQL
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Всем добра.

Имеется процедура, в которой создается и наполняется временная таблица, которая затем "апдейтится".

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
     CREATE TABLE [#sales]
     (
      [dt]          [INT], 
      [StoreID]     [INT], 
      [GoodID]      [INT], 
      [Price]       [FLOAT], 
     );
...
WHILE .... (цикл по датам понедельников за год - около 50)
  UPDATE A
     SET Price = a.Price - b.Price
     FROM [#sales] A
    INNER JOIN [#sales] B ON a.StoreID = b.StoreID AND a.GoodID = b.GoodID AND b.dt = @dt
   WHERE a.dt > b.dt



Приведены не все поля и формула (SET) естественно более сложная, не суть.

В таблице порядка 500 млн строк. Каждый шаг порядка 15 минут (около 200 млн строк затрагивается)
Попробовал добавить индексы StoreID и GoodID - заметного прироста не получилось, а вот на построение индекса времени ушло...

Вопрос - поможет ли в данном случае добавление ID INT IDENTITY(1,1) PRIMARY KEY?
Или нужно дробить запросы на более мелкие (по StoreID или GoodID)
...
Рейтинг: 0 / 0
Большой UPDATE
    #40026041
PizzaPizza
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Oleg_SQLВопрос - поможет ли в данном случае добавление ID INT IDENTITY(1,1) PRIMARY KEY?
У вас нет кластерного индекса на таблице?

Сначала стоит определиться, у вас соединение долго выполняется или только обновление. Сделайте SELECT вместо UPDATE.
Вместо цикла почему не соединяться с календариком понедельников? Это будет одно выполнение вместо десятков.

А вообще не очень понятен INNER JOIN таблицы самой с собой по одним и тем же полям. Какой тут смысл, кроме дублирующихся полей и фильтра по дате?

Код: sql
1.
2.
SELECT * FROM [#sales] A
    INNER JOIN [#sales] B ON a.StoreID = b.StoreID AND a.GoodID = b.GoodID AND b.dt = @dt
...
Рейтинг: 0 / 0
Большой UPDATE
    #40026045
Oleg_SQL
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
PizzaPizza,

в настоящий момент это куча.
смысл цикла что то вроде накопления - берутся данные по неделе и обновляются более поздние данные и так далее...
формула сложная (нужна для дальнейшего анализа).
Подключиться к календарю нельзя, т.к. требуется сначала обновить данные с учетом 1-й недели, а ЗАТЕМ по 2-й, ЗАТЕМ по 3-й и тд
Данные с каждой итерацией меняются.
...
Рейтинг: 0 / 0
Большой UPDATE
    #40026063
aleks222
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Oleg_SQL
PizzaPizza,

в настоящий момент это куча.
смысл цикла что то вроде накопления - берутся данные по неделе и обновляются более поздние данные и так далее...
формула сложная (нужна для дальнейшего анализа).
Подключиться к календарю нельзя, т.к. требуется сначала обновить данные с учетом 1-й недели, а ЗАТЕМ по 2-й, ЗАТЕМ по 3-й и тд
Данные с каждой итерацией меняются.


Увы и ах. Этот бред ~50 раз напрасно перелопачивает "500 млн строк".

Код: sql
1.
2.
3.
4.
5.
UPDATE A
     SET Price = a.Price - b.Price
     FROM [#sales] A
    INNER JOIN [#sales] B ON a.StoreID = b.StoreID AND a.GoodID = b.GoodID AND b.dt = @dt
   WHERE a.dt > b.dt



Пойдите учиться на курсы "SQL для чайников".
...
Рейтинг: 0 / 0
Большой UPDATE
    #40026066
felix_ff
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Oleg_SQL
PizzaPizza,

в настоящий момент это куча.
смысл цикла что то вроде накопления - берутся данные по неделе и обновляются более поздние данные и так далее...
формула сложная (нужна для дальнейшего анализа).
Подключиться к календарю нельзя, т.к. требуется сначала обновить данные с учетом 1-й недели, а ЗАТЕМ по 2-й, ЗАТЕМ по 3-й и тд
Данные с каждой итерацией меняются.


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

индекс по storeId и GooID делать бессмысленно у вас нет такого предиката позволяющего отсечь из выборки превалирующий объем строк. как мне кажется индекс по dt, StoreId, GoodID больше подходит в этом плане
...
Рейтинг: 0 / 0
Большой UPDATE
    #40026070
Фотография alexeyvg
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Oleg_SQL
смысл цикла что то вроде накопления - берутся данные по неделе и обновляются более поздние данные и так далее...
Может, тогда нужно сделать кластерный индекс по dt? (Возможно, лучше по dt, StoreID, GoodID)
Отдельные индексы по StoreID, GoodID смысла не имеют.
...
Рейтинг: 0 / 0
Большой UPDATE
    #40026071
aleks222
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
alexeyvg
Oleg_SQL
смысл цикла что то вроде накопления - берутся данные по неделе и обновляются более поздние данные и так далее...
Может, тогда нужно сделать кластерный индекс по dt? (Возможно, лучше по dt, StoreID, GoodID)
Отдельные индексы по StoreID, GoodID смысла не имеют.


Консилиум у постели мертворожденного?

ЗЫ. Прежде чем индексы строгать - запросы надо писать научиться.
...
Рейтинг: 0 / 0
Большой UPDATE
    #40026082
andreymx
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Oleg_SQL,

правильно ли я понял
вы взяли цену в первый понедельник и отняли ее у всех строк с таким StoreID и GoodID с более поздней датой
затем вы взяли цену во второй понедельник (судя по всему, уже изменённую) и отняли ее у всех строк с таким StoreID и GoodID с более поздней датой
...
Рейтинг: 0 / 0
Большой UPDATE
    #40026088
Фотография alexeyvg
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
andreymx
правильно ли я понял
вы взяли цену в первый понедельник и отняли ее у всех строк с таким StoreID и GoodID с более поздней датой
затем вы взяли цену во второй понедельник (судя по всему, уже изменённую) и отняли ее у всех строк с таким StoreID и GoodID с более поздней датой
Oleg_SQL
Приведены не все поля и формула (SET) естественно более сложная
...
Рейтинг: 0 / 0
Большой UPDATE
    #40026091
Фотография alexeyvg
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Oleg_SQL
Вопрос - поможет ли в данном случае добавление ID INT IDENTITY(1,1) PRIMARY KEY?
Или нужно дробить запросы на более мелкие (по StoreID или GoodID)
А может, лучше одним запросом, без цикла, перелить данные в другую таблицу, сделав все расчёты, а потом сделать переименование?
...
Рейтинг: 0 / 0
Большой UPDATE
    #40026145
andreymx
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
alexeyvg
andreymx
правильно ли я понял
вы взяли цену в первый понедельник и отняли ее у всех строк с таким StoreID и GoodID с более поздней датой
затем вы взяли цену во второй понедельник (судя по всему, уже изменённую) и отняли ее у всех строк с таким StoreID и GoodID с более поздней датой
Oleg_SQL
Приведены не все поля и формула (SET) естественно более сложная
пока непонятна цель расчетов - советы бесполезны
...
Рейтинг: 0 / 0
Большой UPDATE
    #40026250
Oleg_SQL
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
alexeyvg
А может, лучше одним запросом, без цикла, перелить данные в другую таблицу, сделав все расчёты, а потом сделать переименование?


так данные и перелиты в отдельную временную таблицу [#sales]
...
Рейтинг: 0 / 0
Большой UPDATE
    #40026251
Oleg_SQL
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
aleks222
Oleg_SQL
PizzaPizza,

в настоящий момент это куча.
смысл цикла что то вроде накопления - берутся данные по неделе и обновляются более поздние данные и так далее...
формула сложная (нужна для дальнейшего анализа).
Подключиться к календарю нельзя, т.к. требуется сначала обновить данные с учетом 1-й недели, а ЗАТЕМ по 2-й, ЗАТЕМ по 3-й и тд
Данные с каждой итерацией меняются.


Увы и ах. Этот бред ~50 раз напрасно перелопачивает "500 млн строк".

Код: sql
1.
2.
3.
4.
5.
UPDATE A
     SET Price = a.Price - b.Price
     FROM [#sales] A
    INNER JOIN [#sales] B ON a.StoreID = b.StoreID AND a.GoodID = b.GoodID AND b.dt = @dt
   WHERE a.dt > b.dt



Пойдите учиться на курсы "SQL для чайников".


Научитесь ВНИМАТЕЛЬНО читать для начала.
Приведены не все поля и формула (SET) естественно более сложная, не суть.
...
Рейтинг: 0 / 0
Большой UPDATE
    #40026256
Oleg_SQL
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
alexeyvg
Oleg_SQL
смысл цикла что то вроде накопления - берутся данные по неделе и обновляются более поздние данные и так далее...
Может, тогда нужно сделать кластерный индекс по dt? (Возможно, лучше по dt, StoreID, GoodID)
Отдельные индексы по StoreID, GoodID смысла не имеют.



Спасибо, попробую.
Почему собственно вопрос то и возник - затраты по времени на построение индекса иногда съедают всю выгоду от них (не менее часа, думаю будет длится). И одной только теорией, без пробы не обойтись.
...
Рейтинг: 0 / 0
Большой UPDATE
    #40026262
Фотография alexeyvg
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Oleg_SQL
alexeyvg
А может, лучше одним запросом, без цикла, перелить данные в другую таблицу, сделав все расчёты, а потом сделать переименование?


так данные и перелиты в отдельную временную таблицу [#sales]
Так и не надо там их апдэйтить. Переливайте ещё в одну таблицу.
Или сразу заливайте в эту с расчётом, чего бы сразу не посчитать правильно, зачем потом корректировать?
Oleg_SQL
Спасибо, попробую.
Почему собственно вопрос то и возник - затраты по времени на построение индекса иногда съедают всю выгоду от них (не менее часа, думаю будет длится). И одной только теорией, без пробы не обойтись.
Тут вопрос, во первых, в самой операции апдэйта - это нелёгкая операция для сервера, во вторых, в массивном и многократном джойне таблицы самой с собой - зачем апдэйтить много раз, если можно посчитать сразу? Вы сколько раз обновляете таблицу, столько, сколько дней за всё время??? Это же ужас.

Другое дело, что, возможно, логически вычисления очень непростые, и сложно их переделать на один проход.
Но другого выхода нет, придётся поскрипеть мозгами, ибо такой апдэйт - это трэш :-)
...
Рейтинг: 0 / 0
Большой UPDATE
    #40026266
L_argo
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Никакие индексы-шминдексы не помогут, ИМХО.
Реально ускориться можно одним способом - как-то реорганизовать работу с данными.

Н-р где-то отдельно делать расчеты, а потом накатывать готовые результаты на сабжевую таблицу.
...
Рейтинг: 0 / 0
Большой UPDATE
    #40026273
Oleg_SQL
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
alexeyvg,


Алгоритм расчета такой, что однозначно нужно считать каждую неделю с учетом предыдущих данных.

Смысл такой, что для каждого товара нужно брать последнюю цену (акцию, кпи, признаки и тп) и на их основе считать показатели для текущей в итерации недели. Последняя цена не всегда на прошлой неделе - может быть и пол года назад.
Сейчас берется неделя и апдейтся все последующие данные (от той недели до сегодня) и так далее. Это позволяет избежать эти пропуски - как только есть цена для товара, то для последующих периодов она уже засветится, и будет неизменна до нового значения. Примитивно, но запрос простой, он работает и выдает верный результат.

Можно менять данные не для всего периода, а только для конкретной недели - это все будет на порядок быстрее.
Как для 500 млн товаров (по точкам) проапдейтить данные на основе последних показателей по каждому я знаю. Но конструкция выборки этих последних данных выглядит более зловеще )))
В любом случае придется попробовать и его.
...
Рейтинг: 0 / 0
Большой UPDATE
    #40026276
invm
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Oleg_SQL,

У вашего подхода есть две проблемы:
1. Из-за отсутствия ограничений/индексов оптимизатор считает, что одна и та же строка может быть обновлена несколько раз. Поэтому в план будет включено исключение таких дубликатов.
2. Такой update предполагает наличие halloween problem. Соответственно в план будет включена защита, скорее всего в виде Eager Table Spool

Если критерий уникальности - (dt, StoreID, GoodID), то сделайте у #sales PK по этим столбцам, dt обязательно должен быть первым.
Тогда первая проблема отпадет.
Для избавления от второй, предварительно отбирайте строки по dt = @dt во временную таблицу и соответствующим образом перепишите update.
...
Рейтинг: 0 / 0
Большой UPDATE
    #40026278
andreymx
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Для таких алгоритмов надо где-то хранить эти промежуточные данные и считать каждый месяц, например
Рассчитывать их каждый раз - моветон
...
Рейтинг: 0 / 0
Большой UPDATE
    #40026283
Oleg_SQL
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
andreymx
Для таких алгоритмов надо где-то хранить эти промежуточные данные и считать каждый месяц, например
Рассчитывать их каждый раз - моветон


Я это все прекрасно понимаю. Но вот данные меняют задним числом (приходят корректировки и тп).
Это в 1С есть понятие закрытий период. В данной системе такого нет. Пересчет за 2 месяца выполняется 1 раз в месяц - не так критично.
...
Рейтинг: 0 / 0
Большой UPDATE
    #40026289
Владислав Колосов
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Oleg_SQL,

а как вы бухгалтерскую отчетность поддерживаете? Я понимаю, что так поступали в 90х, но сейчас без закрытия периода никак нельзя.
...
Рейтинг: 0 / 0
Большой UPDATE
    #40026298
Oleg_SQL
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Владислав Колосов
Oleg_SQL,

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


Это данные не для строгой отчетности.
...
Рейтинг: 0 / 0
Большой UPDATE
    #40026312
andreymx
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Олег
А сам расчёт работает корректно, Но медленно?
...
Рейтинг: 0 / 0
Большой UPDATE
    #40026314
andreymx
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
andreymx
Олег
А сам расчёт работает корректно, Но медленно?
дождался кто-нибудь окончания? :)
...
Рейтинг: 0 / 0
Большой UPDATE
    #40026322
Oleg_SQL
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
andreymx
andreymx
Олег
А сам расчёт работает корректно, Но медленно?
дождался кто-нибудь окончания? :)


Работает корректно. Но медленно. Все верно.
Запрос написан не мной. И по принципу работает - не трогай я хотел оптимизировать его не внося корректировку в код. Не особо погружаясь в логику.
Видимо придется погрузиться и внести кардинальные изменения (чувствую, что это возможно).

P.S. Кластерный индекс строится уже более часа...
...
Рейтинг: 0 / 0
Большой UPDATE
    #40026410
Фотография alexeyvg
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Oleg_SQL
alexeyvg,

Алгоритм расчета такой,что однозначно нужно считать каждую неделю с учетом предыдущих данных.

Вы говорите "нужно считать каждую неделю с учетом предыдущих данных", а в запросе вы делаете другое - считаете все следующие записи по текущей записи, потом считаете все следующие записи по следующей записи, и т.д.
Это очень сильно отличается.

"нужно считать каждую неделю с учетом предыдущих данных" в какой то степени похоже на "накопительный итог", это можно считать, не апдэйтя данные за всё время столько раз, сколько строк в таблице ,а за один проход.
И, конечно, не апдэйтя таблицу, а вставляя в новую.
Тогда у вас общее время пересчёта по сути будет равно одному скану таблицы (правда, будут затраты памяти, для хранения накопительных счётчиков, по числу сочетаний StoreID и GoodID)
То есть в тыщи раз быстрее, чем сейчас.
...
Рейтинг: 0 / 0
Большой UPDATE
    #40026431
Oleg_SQL
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
alexeyvg,

alexeyvg,

Запрос:
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
             UPDATE [snp]
               SET 
                   [DevReg] =   IIF([snp].[Price] = 0, 0, ROUND(([snp].[Price] - [snpPrev].[PriceReg]) / [snp].[Price], 2)), 
                   [DevPromo] = IIF([snp].[Price] = 0, 0, ROUND(([snp].[Price] - [snpPrev].[PricePromo]) / [snp].[Price], 2)), 
                   [isPromo] =  IIF([snp].[Price] <> 0
                                    AND ([snp].[Price] - [snpPrev].[PriceReg]) / [snp].[Price] < -0.11
                                    AND ([snp].[Price] - [snpPrev].[PricePromo]) / [snp].[Price] < 0.23, 
								1, 0), 
                   [PriceReg] = IIF([snp].[Price] <> 0
                                    AND ([snp].[Price] - [snpPrev].[PriceReg]) / [snp].[Price] < -0.11
                                    AND ([snp].[Price] - [snpPrev].[PricePromo]) / [snp].[Price] < 0.23, 
								 [snpPrev].[PriceReg], [snp].[Price]), 
                   [PricePromo] = IIF([snp].[Price] <> 0
                                     AND ([snp].[Price] - [snpPrev].[PriceReg]) / [snp].[Price] < -0.11
                                     AND ([snp].[Price] - [snpPrev].[PricePromo]) / [snp].[Price] < 0.23, 
								  [snp].[Price], [snpPrev].[PricePromo])
             FROM [#salesPromo] AS [snp]
             -- Поиск значений предыдущей записи
                  INNER JOIN [#salesPromo] AS [snpPrev] ON 1 = 1
                                  AND [snp].[dt] > [snpPrev].[dt]
                                  AND [snpPrev].[dt] = @dt
                                  AND [snp].[StoreID] = [snpPrev].[StoreID]
                                  AND [snp].[GoodID] = [snpPrev].[GoodID]
								  AND snp.ChildGoodID = snpPrev.ChildGoodID
             WHERE [snp].[dt] BETWEEN @dtnext AND @curperiodend



В идеале вместо WHERE [snp].[dt] BETWEEN @dtnext AND @curperiodend нужно WHERE [snp].[dt] =@dtnext
Т.е. брать данные одной недели и апдейтить их данными предыдущей.
Но на предыдущей неделе может не быть данных по товару - они были 5/6/12... недель назад. Поэтому делается апдейт всего что после текущей (@dt), а как дойдет до недели где опять есть этот товар, то по нему проапдейтится сново все далее...

Одним запросом это сделать - не могу сообразить как.
Ведь данные по каждой неделе постоянно меняются и 10 неделя до начала расчета будет не той как после 2, 3 и тп шагов...

По идее вот я получил данные по товару Х за 1 неделю и мне нужно не все со 2-й по 50-ю неделю обновлять, а только первую неделю где есть этот товар. Лишь в этом я вижу возможность уменьшить число строк для обновления.
Т.е. нечто типа OUTER APPLY (SELECT TOP 1 ... )
...
Рейтинг: 0 / 0
Большой UPDATE
    #40026454
Oleg_SQL
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Сделал так, чтобы наоборот для выбранной недели находились прошлые данные

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
    UPDATE [snp]
               SET 
                   [DevReg] =   IIF([snp].[Price] = 0, 0, ROUND(([snp].[Price] - [snpPrev].[PriceReg]) / [snp].[Price], 2)), 
                   [DevPromo] = IIF([snp].[Price] = 0, 0, ROUND(([snp].[Price] - [snpPrev].[PricePromo]) / [snp].[Price], 2)), 
                   [isPromo] =  IIF([snp].[Price] <> 0
                                    AND ([snp].[Price] - [snpPrev].[PriceReg]) / [snp].[Price] < -0.11
                                    AND ([snp].[Price] - [snpPrev].[PricePromo]) / [snp].[Price] < 0.23, 
								1, 0), 
                   [PriceReg] = IIF([snp].[Price] <> 0
                                    AND ([snp].[Price] - [snpPrev].[PriceReg]) / [snp].[Price] < -0.11
                                    AND ([snp].[Price] - [snpPrev].[PricePromo]) / [snp].[Price] < 0.23, 
								 [snpPrev].[PriceReg], [snp].[Price]), 
                   [PricePromo] = IIF([snp].[Price] <> 0
                                     AND ([snp].[Price] - [snpPrev].[PriceReg]) / [snp].[Price] < -0.11
                                     AND ([snp].[Price] - [snpPrev].[PricePromo]) / [snp].[Price] < 0.23, 
								  [snp].[Price], [snpPrev].[PricePromo])
             FROM [#salesPromo] AS [snp]

            OUTER APPLY (SELECT TOP 1 [dt], [StoreID], [GoodID], [ChildGoodID], 
				                  ISNULL([Price], 0) [Price],ISNULL([DevReg], 0) [DevReg],
						  ISNULL([DevPromo], 0) [DevPromo],
                                                  ISNULL([isPromo], 0) [isPromo],
						  ISNULL([PriceReg], 0) [PriceReg],
						  ISNULL([PricePromo], 0) [PricePromo] 				  
				  FROM [#salesPromo] AS b 
                                  WHERE 1 = 1
                                            AND b.[dt] >= @startweek AND b.[dt] < [snp].[dt]
                                            AND [snp].[StoreID] = b.[StoreID]
                                            AND [snp].[GoodID] = b.[GoodID]
				           AND snp.ChildGoodID = b.ChildGoodID
				  ORDER BY b.Dt DESC
                                ) [snpPrev]
             WHERE [snp].[dt] = @dt and [snpPrev].dt IS NOT NULL



Стало медленнее раза в 3.
В добавок, OUTER APPLY при больших объемах у нас уже вызывал полное зависание (проц = 0%, диск = 0% и тп) при этом ошибок не давал.
...
Рейтинг: 0 / 0
Большой UPDATE
    #40026487
PizzaPizza
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
автор OUTER APPLY (SELECT TOP 1 ...)
да по куче, да с таким количеством предикатов...
...
Рейтинг: 0 / 0
Большой UPDATE
    #40026506
Владислав Колосов
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Oleg_SQL,

OUTER APPLY ... order by

откуда там взяться производительности.
...
Рейтинг: 0 / 0
Большой UPDATE
    #40026520
Фотография alexeyvg
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Oleg_SQL
Одним запросом это сделать - не могу сообразить как.
Функция
LAG (Price) OVER ( [ partition by StoreID, GoodID order by dt) вернёт вам значение Price для тех же StoreID и GoodID за предыдущий день
...
Рейтинг: 0 / 0
Большой UPDATE
    #40026529
Фотография alexeyvg
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Oleg_SQL
Стало медленнее раза в 3.
В добавок, OUTER APPLY при больших объемах у нас уже вызывал полное зависание (проц = 0%, диск = 0% и тп) при этом ошибок не давал.
И при этом был кластерный индекс на dt, StoreID, GoodID, ChildGoodID? (хотя бы на первые 2-3 поля)

Без индекса это неприемлемо (как и вариант с LAG)
...
Рейтинг: 0 / 0
Большой UPDATE
    #40026532
Фотография alexeyvg
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Oleg_SQL
затраты по времени на построение индекса иногда съедают всю выгоду от них (не менее часа, думаю будет длится)
Индексы должны быть в базе.
Не для расчёта, а вообще, и не надо их строить-удалять
...
Рейтинг: 0 / 0
Большой UPDATE
    #40026690
Oleg_SQL
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
alexeyvg
Oleg_SQL
Стало медленнее раза в 3.
В добавок, OUTER APPLY при больших объемах у нас уже вызывал полное зависание (проц = 0%, диск = 0% и тп) при этом ошибок не давал.
И при этом был кластерный индекс на dt, StoreID, GoodID, ChildGoodID? (хотя бы на первые 2-3 поля)

Без индекса это неприемлемо (как и вариант с LAG)


Я конечно не профессор, но кластерный индекс был построен по всем указанным полям.
В данный момент я добавил при вставке во временную таблицу поле rn (row_number) и добавил его в кластерный индекс.
Теперь добавил условие в INNER JOIN : AND snp.RN = snpPrev.RN + 1
Обработка взлетела ))
Вот только много времени уходит на саму вставку в #salesPromo со всеми индексами и row_number(OVER(PARTITION BY... ORDER BY...).
...
Рейтинг: 0 / 0
Большой UPDATE
    #40026739
Oleg_SQL
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
alexeyvg
Oleg_SQL
Одним запросом это сделать - не могу сообразить как.
Функция
LAG (Price) OVER ( [ partition by StoreID, GoodID order by dt) вернёт вам значение Price для тех же StoreID и GoodID за предыдущий день



Код: sql
1.
2.
3.
4.
DECLARE @T TABLE (dt int, val int)
INSERT @T VALUES (20200101, 100), (20200108, NULL), (20200115, NULL), (20200122, 120)
SELECT *, LAG(Val) OVER(ORDER BY dt) as lastvalue
FROM @T



dt val lastvalue
----------- ----------- -----------
20200101 100 NULL
20200108 NULL 100
20200115 NULL NULL
20200122 120 NULL

а мне нужно для 20200122 значение lastvalue = 100. Последнее не пустое значение , а не значение прошлой строки.
...
Рейтинг: 0 / 0
Большой UPDATE
    #40026743
Oleg_SQL
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
alexeyvg
Oleg_SQL
затраты по времени на построение индекса иногда съедают всю выгоду от них (не менее часа, думаю будет длится)
Индексы должны быть в базе.
Не для расчёта, а вообще, и не надо их строить-удалять


я же в расчете использую временную таблицу... как им там быть то?
...
Рейтинг: 0 / 0
Большой UPDATE
    #40026776
felix_ff
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Oleg_SQL,

вы индекс строите после заполнения таблицы или до?
...
Рейтинг: 0 / 0
Большой UPDATE
    #40026813
Oleg_SQL
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
felix_ff
Oleg_SQL,

вы индекс строите после заполнения таблицы или до?


Конечно же ДО
...
Рейтинг: 0 / 0
Большой UPDATE
    #40026819
felix_ff
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Oleg_SQL,

В таком случае что там у вас с планом запроса наполнения временной таблицы? есть ли оператор сортировки?

Для такого некислого объема вставка по определению может быть не особо быстрой.
...
Рейтинг: 0 / 0
Большой UPDATE
    #40026831
Oleg_SQL
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
felix_ff
Oleg_SQL,

В таком случае что там у вас с планом запроса наполнения временной таблицы? есть ли оператор сортировки?

Для такого некислого объема вставка по определению может быть не особо быстрой.


Со вставкой уже ничего не поделаешь - манипулировать с рабочей таблицей (индексы и тп) мне не дают.
...
Рейтинг: 0 / 0
Большой UPDATE
    #40026862
Фотография alexeyvg
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Oleg_SQL
а мне нужно для 20200122 значение lastvalue = 100. Последнее не пустое значение , а не значение прошлой строки.
Подождите, вы же в последнем запросе ищите именно "значение прошлой строки", и не "Последнее не пустое значение "
Код: sql
1.
2.
3.
4.
5.
OUTER APPLY (SELECT TOP 1 [dt], [StoreID], [GoodID], [ChildGoodID], 
...
	FROM [#salesPromo] AS b 
...
	ORDER BY b.Dt DESC
...
Рейтинг: 0 / 0
Большой UPDATE
    #40026866
Фотография alexeyvg
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Oleg_SQL
alexeyvg
пропущено...
Индексы должны быть в базе.
Не для расчёта, а вообще, и не надо их строить-удалять


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

Другое дело, что схема исходных таблиц сложнее, и по ней не получится так легко сделать интересующий сложный запрос.
...
Рейтинг: 0 / 0
Большой UPDATE
    #40026877
0wl
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
0wl
Гость
Oleg_SQL,

Вообще есть смысл строить все индексы уже после наполнения временной таблицы. Сначала кластерный, потом некластерные, если есть.

Если вы построите индекс по существующим данным, вместе с индексом построится актуальная статистика. А если наоборот - останется только надеяться на автопересчет статистик.
...
Рейтинг: 0 / 0
Большой UPDATE
    #40026880
Oleg_SQL
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
[quot alexeyvg#22246312]
Oleg_SQL
а мне нужно для 20200122 значение lastvalue = 100. Последнее не пустое значение , а не значение прошлой строки.
Подождите, вы же в последнем запросе ищите именно "значение прошлой строки", и не "Последнее не пустое значение "

Да, всё верно. Я уже заметил и поправил. На скорость это не повлияло.
Но это был тестовый запрос для успокоения души ))
...
Рейтинг: 0 / 0
Большой UPDATE
    #40026884
Oleg_SQL
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
0wl
Oleg_SQL,

Вообще есть смысл строить все индексы уже после наполнения временной таблицы. Сначала кластерный, потом некластерные, если есть.

Если вы построите индекс по существующим данным, вместе с индексом построится актуальная статистика. А если наоборот - останется только надеяться на автопересчет статистик.



Записать 500 млн записей, а потом начать строить кластерный индекс? Это будет реально быстрее?
...
Рейтинг: 0 / 0
Большой UPDATE
    #40026979
0wl
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
0wl
Гость
Oleg_SQL



Записать 500 млн записей, а потом начать строить кластерный индекс? Это будет реально быстрее?


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

Если сначала залить данные в кучу, а потом построить по ним индекс, они запишутся 2 раза. И нужно будет выделить место в файле данных для создания индекса. Зато можно использовать BULK INSERT (ну или SELECT … INTO) и ускорить первоначальную вставку в кучу. (см. https://docs.microsoft.com/en-US/sql/relational-databases/import-export/prerequisites-for-minimal-logging-in-bulk-import?view=sql-server-ver15#table-requirements-for-minimally-logging-bulk-import-operations)

С другой стороны, если данные заливаются в кластерный индекс пачками, в несколько транзакций, то в процессе заливки несколько раз сработает автоапдейт статистик. Но это чтения, а не запись, к тому же, чтения какого-то сэмпла, а не всей таблицы.

В общем, я бы замерил варианты. Ну и если выбирать второй вариант, то по окончании заливки пересчитал бы статистику с FULLSCAN, чтобы гарантировать, что план будет эффективным.
...
Рейтинг: 0 / 0
Большой UPDATE
    #40027013
Фотография alexeyvg
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
0wl
Зато можно использовать BULK INSERT (ну или SELECT … INTO) и ускорить первоначальную вставку в кучу.
С минимальным логированием можно и не в кучу записывать.
Но надо одной операцией, а не "пачками".
...
Рейтинг: 0 / 0
Большой UPDATE
    #40027015
Фотография alexeyvg
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Oleg_SQL
Да, всё верно. Я уже заметил и поправил. На скорость это не повлияло.
Но это был тестовый запрос для успокоения души ))
А вот тут вы тогда тоже ошиблись?
Oleg_SQL
В идеале вместо WHERE [snp].[dt] BETWEEN @dtnext AND @curperiodend нужно WHERE [snp].[dt] =@dtnext
Т.е. брать данные одной недели и апдейтить их данными предыдущей.
Но на предыдущей неделе может не быть данных по товару - они были 5/6/12... недель назад. Поэтому делается апдейт всего что после текущей (@dt), а как дойдет до недели где опять есть этот товар, то по нему проапдейтится сново все далее...

Как я понял, у вас отсутствие данных означает не наличие записи во значением поля Price, равным NULL, а именно отсутствие записи.

Если "отсутствие данных" означает "отсутствие записи", то цикл апдэйтов заменяется на рекурсивный CTE по датам, с заменой OUTER APPLY на LAG, и на итоговую вставку в таблицу результата, соответственно, с возможностью использовать индексы постоянных таблиц

Тогда всё будет кардинально быстрее.

Ну или вообще нужно менять модель данных, на что выше намекали, но на это вы вряд ли пойдёте, это уже не "оптимизация", а "перепроектирование системы".
...
Рейтинг: 0 / 0
48 сообщений из 48, показаны все 2 страниц
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / Большой UPDATE
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]