powered by simpleCommunicator - 2.0.60     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / Переписать запрос для использования в индексированном представлении
17 сообщений из 17, страница 1 из 1
Переписать запрос для использования в индексированном представлении
    #39840130
Alexey30
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Добрый день.
Есть запрос, который работает хорошо и вариантов которого можно представить несколько, но никак не пойму, как сделать его пригодным для того, чтобы на его основе создать индексированное представление. To нельзя использовать Min/Max, то получается SelfJoin, то еще чего-то.
Подтолкните, пожалуйста, к верному решению.

Таблицы:
SKUsEvents (SKUsEventID, EventDate, SKUsEventsTypeID, ....) - таблица событий, описывает дату события, тип и другие параметры.
SKUsEventsSKUs - (SKUsEventID, SKU, Quan) указывает, какие конкретно товарные позиции были в данном событии, с указанием количества.
SKUsCapsulesTrans - (SKU1, SKU2, ResultSKU) - используется только для определенного типа событий, как раз из-за которого эта вьюха и нужна (сборка, когда точно известно, что из двух конкретных SKU получается один конкретный третий). SKU2 всего больше SKU1.

Таким образом, для всех событий с SKUsEventsTypeID = 11 в таблице SKUsEventsSKUs всегда ТОЛЬКО ДВЕ строки, из которых можно понять, что конкретно взяли для сборки. Задача - получить вьюху "готовых" продуктов.

Решение 1:
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
SELECT t.SKUsEventID ,
       t.EventDate ,
       t.FromWarehouseID WarehouseID,
       sct.SKUResult SKU,
	   Quan
FROM 
(
	SELECT  se.SKUsEventID, se.EventDate, se.FromWarehouseID, MIN(ses.SKU) SKU1Out, MAX(ses.SKU) SKU2Out, MAX(ses.Quan) Quan
	FROM dbo.SKUsEvents se
	INNER JOIN dbo.SKUsEventsSKUs ses ON ses.SKUsEventID = se.SKUsEventID
	WHERE se.SKUsEventsTypeID = 11
	GROUP BY se.SKUsEventID, se.EventDate, se.FromWarehouseID
) t
INNER JOIN dbo.SKUsCapsulesTrans sct ON sct.SKU1 = t.SKU1Out AND sct.SKU2=t.SKU2Out



Решение 2 (без агрегатов, но с SelfJoin):
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
SELECT  
	se.SKUsEventID, 
	se.EventDate, 
	se.FromWarehouseID WarehouseID, 
	sct.SKUResult SKU,
	ses.Quan
FROM dbo.SKUsEvents se
INNER JOIN dbo.SKUsEventsSKUs ses ON ses.SKUsEventID = se.SKUsEventID
INNER JOIN dbo.SKUsEventsSKUs ses2  ON ses2.SKUsEventID = ses.SKUsEventID AND ses2.SKU > ses.SKU
INNER JOIN dbo.SKUsCapsulesTrans sct ON sct.SKU1 = ses.SKU AND sct.SKU2= ses2.SKU
WHERE se.SKUsEventsTypeID = 11



Есть мысль переделать SKUsCapsulesTrans в структуру вида
(SKUSource, SKUResult, VariantID), где последняя колонка будет служить для группировки по "правильным сочетаниям", но тут тоже не уверен, что сразу все получится..
...
Рейтинг: 0 / 0
Переписать запрос для использования в индексированном представлении
    #39840139
Alexey30
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Если SKUsCapsulesTrans переделать в такой вид (SKUSource, SKUResult, VariantID), то получится такой запрос.

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
SELECT  
	se.SKUsEventID, 
	se.EventDate,
	se.FromWarehouseID,
	sct2.SKUResult SKU,
	ses.Quan
FROM dbo.SKUsEvents se
INNER JOIN dbo.SKUsEventsSKUs ses ON ses.SKUsEventID = se.SKUsEventID
INNER JOIN dbo.SKUsCapsulesTrans2 sct2 ON sct2.SKUSource=ses.SKU
WHERE se.SKUsEventsTypeID = 11
GROUP BY 
	se.SKUsEventID, 
	se.EventDate,
	se.FromWarehouseID,
	sct2.Variant,
	sct2.SKUResult,
	ses.Quan 
HAVING COUNT_BIG(*) = 2



Но HAVING тоже нельзя(((
...
Рейтинг: 0 / 0
Переписать запрос для использования в индексированном представлении
    #39840142
Alexey30
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Еще один вариант - это разнести на два события с одинаковой датой: первое будет ввод (с двумя SKU), второе - вывод - с одним.
Это тогда решит все проблемы с индексированной вьюхой, но будет избыточность и как-то не очень красиво это.
...
Рейтинг: 0 / 0
Переписать запрос для использования в индексированном представлении
    #39840369
Владислав Колосов
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Alexey30,

без наборов данных непонятно - что на входе и что надо получить на выходе.
...
Рейтинг: 0 / 0
Переписать запрос для использования в индексированном представлении
    #39840404
Alexey30
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Добрый день.
Примерно такой набор тестовых данных, если опустить все лишнее.


Код: 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.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
CREATE TABLE SKUs (SKU INT, Title VARCHAR(50))
CREATE TABLE SKUsEventsTypes (SKUsEventsTypeID int, Title VARCHAR(50))
CREATE TABLE SKUsEvents (SKUsEventID int, EventDate DATETIME, SKUsEventsTypeID INT, WarehouseID int)
CREATE TABLE SKUsEventsSKUs (SKUsEventID int, SKU int, Quan int)
CREATE TABLE SKUsCapsulesTrans (SKU1 int, SKU2 int, SKUResult INT)

INSERT  dbo.SKUsEventsTypes
        ( SKUsEventsTypeID, Title )
VALUES  ( 1, 'Закупка'), ( 2, 'Перемещение'), ( 11, 'Сборка двух товаров в один')

INSERT dbo.SKUs
        ( SKU, Title )
VALUES  ( 1, 'Товар 1'), (2, 'Товар 2'), (3, 'Товар 3'), (3, 'Товар 4'), (3, 'Товар 5 (состоит из 1 и 2)'), (3, 'Товар 6 (состоит из 1 и 3)')

INSERT dbo.SKUsCapsulesTrans
        ( SKU1, SKU2, SKUResult )
VALUES  (1,2,5), (1,3,6) --указываем, из каких товаров какие можно собрать (всегда два на входе, один на выходе)

INSERT SKUsEvents (SKUsEventID, EventDate, SKUsEventsTypeID, WarehouseID)
VALUES 
	(1, '01.01.2000', 1, 1), --закупка
	(2, '02.01.2000', 11, 1) --сборка

INSERT dbo.SKUsEventsSKUs
        ( SKUsEventID, SKU, Quan )
VALUES  (1, 1, 10), (1, 2, 10), (1, 3, 10), (1, 4, 10) --закупаем товары 1-4 по 10 шт

INSERT dbo.SKUsEventsSKUs
        ( SKUsEventID, SKU, Quan )
VALUES  (2, 1, 4), (2, 2, 4) --собираем Товар 5 из товаров 1 и 2
 
 --далее нужно получить список товаров, которые получились после сборки, используем любой из селектов выше.

 SELECT t.SKUsEventID ,
       t.EventDate ,
       WarehouseID,
       sct.SKUResult SKU,
	   Quan
FROM 
(
	SELECT  se.SKUsEventID, se.EventDate, se.WarehouseID, MIN(ses.SKU) SKU1Out, MAX(ses.SKU) SKU2Out, MAX(ses.Quan) Quan
	FROM dbo.SKUsEvents se
	INNER JOIN dbo.SKUsEventsSKUs ses ON ses.SKUsEventID = se.SKUsEventID
	WHERE se.SKUsEventsTypeID = 11
	GROUP BY se.SKUsEventID, se.EventDate, se.WarehouseID
) t
INNER JOIN dbo.SKUsCapsulesTrans sct ON sct.SKU1 = t.SKU1Out AND sct.SKU2=t.SKU2Out



На выходе получаем
Код: sql
1.
2.
SKUsEventID	EventDate	WarehouseID	SKU	Quan
2	2000-01-02 	1	5	4
...
Рейтинг: 0 / 0
Переписать запрос для использования в индексированном представлении
    #39840418
Фотография Yasha123
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
если так уж хочется имитировать индексированное представление,
сами храните и поддерживайте в отдельной таблице свои MIN(SKU), MAX(SKU).
сервер это не делает по простой причине:
если в вашей таблицы проайпэйтит строку, то пересчитывать COUNT_BIG(*) ему не надо:
счетчик просто не изменится
(при вставке строки увеличится, при удалении уменьшится)
а как, простите, пересчитать MIN и MAX, не сканируя всю таблицу?
может, вы как раз своим апдэйтом истребили предыдущий MIN/MAX?
...
Рейтинг: 0 / 0
Переписать запрос для использования в индексированном представлении
    #39840476
Владислав Колосов
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Alexey30,

от сортировка Вы никуда не уйдёте. Для быстрой выборки вам надо создать витрину, которая будет обновлять min/max при изменениях исходных таблиц. Всегда жертвуешь или скоростью или объёмом хранения.
...
Рейтинг: 0 / 0
Переписать запрос для использования в индексированном представлении
    #39840505
uaggster
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Alexey30, Просто разделите ваш запрос на 2 представления.
В одном, индексированном, храните исходные данные, а второе, с группировками, мин и макс - сделайте обычным.
Ну, т.е. если весь запрос нельзя сделать индексированным представлением, сделайте максимально возможную заготовку, и обычное представление, его использующее.
...
Рейтинг: 0 / 0
Переписать запрос для использования в индексированном представлении
    #39840544
Фотография Yasha123
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
uaggsterAlexey30, Просто разделите ваш запрос на 2 представления.
В одном, индексированном, храните исходные данные, а второе, с группировками, мин и макс - сделайте обычным.
Ну, т.е. если весь запрос нельзя сделать индексированным представлением, сделайте максимально возможную заготовку, и обычное представление, его использующее.
смысл сего действа в чем?
индексированное представление не пересчитывает агрегаты типа count()
при обновлении таблиц.
а если их все равно придется пересчитывать в вашем "просто представлении" (скан + сорт),
то зачем весь этот огород?
...
Рейтинг: 0 / 0
Переписать запрос для использования в индексированном представлении
    #39840625
uaggster
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Yasha123uaggsterAlexey30, Просто разделите ваш запрос на 2 представления.
В одном, индексированном, храните исходные данные, а второе, с группировками, мин и макс - сделайте обычным.
Ну, т.е. если весь запрос нельзя сделать индексированным представлением, сделайте максимально возможную заготовку, и обычное представление, его использующее.
смысл сего действа в чем?
индексированное представление не пересчитывает агрегаты типа count()
при обновлении таблиц.
а если их все равно придется пересчитывать в вашем "просто представлении" (скан + сорт),
то зачем весь этот огород?
Ну сузить же набор данных, с которым работает запрос, который потом считает min, max и count. И построить по этому набору кастомные индексы, если их напрямую нельзя по каким-то причинам построить по исходным таблицам.
Для чего еще indexed view нужны?
Нет, я понимаю, что может быть, в данном конкретном случае этот совет сродни "мыши, станьте ежиками".
Но, вообще - нормально это работает. Вырезать из звездообразного соединения те поля, которые нужны, отсечь, например, началом года, и построить индексы по полям, которые в родных таблицах в качестве индексируемых - не фигурируют.
Чем плохо то?
Даже по вертикально суженной выборке - агрегаты будут быстрее считаться, в отличие от исходных "широких таблиц".
И потом, columnstore можно и поверх индексированного представления создать
http://www.nikoport.com/2016/10/10/columnstore-indexes-part-87-indexed-views/
(не пробовал, кстати).
...
Рейтинг: 0 / 0
Переписать запрос для использования в индексированном представлении
    #39840628
invm
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Alexey30Если SKUsCapsulesTrans переделать в такой вид (SKUSource, SKUResult, VariantID)Можете так извратиться:
Код: 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.
34.
35.
36.
37.
38.
39.
40.
create MyIndexedView
with schemabinding
as
SELECT  
	se.SKUsEventID, 
	se.EventDate,
	se.FromWarehouseID,
    sct2.Variant,
	sct2.SKUResult,
	ses.Quan,
    COUNT_BIG(*) as cnt
FROM dbo.SKUsEvents se
INNER JOIN dbo.SKUsEventsSKUs ses ON ses.SKUsEventID = se.SKUsEventID
INNER JOIN dbo.SKUsCapsulesTrans2 sct2 ON sct2.SKUSource=ses.SKU
WHERE se.SKUsEventsTypeID = 11
GROUP BY 
	se.SKUsEventID, 
	se.EventDate,
	se.FromWarehouseID,
	sct2.Variant,
	sct2.SKUResult,
	ses.Quan ;
go

create unique clustered index CUIX_MyIndexedView on MyIndexedView (cnt, SKUsEventID, EventDate, FromWarehouseID, Variant, SKUResult, Quan);
go

create MyView
as
select
 SKUsEventID, 
 EventDate,
 FromWarehouseID,
 SKUResult SKU,
 Quan
from
 MyIndexedView with (noexpand)
where
 cnt = 2;
go
...
Рейтинг: 0 / 0
Переписать запрос для использования в индексированном представлении
    #39840632
Фотография Yasha123
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
uaggsterДаже по вертикально суженной выборке - агрегаты будут быстрее считаться, в отличие от исходных "широких таблиц".
И потом, columnstore можно и поверх индексированного представления создать

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

вот тогда хранить их в таблице в 1 строку и самому обновлять
...
Рейтинг: 0 / 0
Переписать запрос для использования в индексированном представлении
    #39840641
uaggster
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Yasha123uaggsterДаже по вертикально суженной выборке - агрегаты будут быстрее считаться, в отличие от исходных "широких таблиц".
И потом, columnstore можно и поверх индексированного представления создать

так columnstore и без вью можно создать.
и считать агрегаты быстрее.

Флейма для: Дык весь смысл вырезать из звездочки заготовку, и уже по ней построить колумнстор. Эдакое эрзац - хранилище.
...
Рейтинг: 0 / 0
Переписать запрос для использования в индексированном представлении
    #39840668
Владислав Колосов
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
uaggster,

это называется "витрина".
...
Рейтинг: 0 / 0
Переписать запрос для использования в индексированном представлении
    #39840690
Фотография Yasha123
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
uaggster,
а кск вы колумнсторы в 2014 Standard делаете?
...
Рейтинг: 0 / 0
Переписать запрос для использования в индексированном представлении
    #39840695
Alexey30
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Огромное спасибо всем за уделенное время и внимание.
Видимо, остановлюсь на варианте от invm.

invm, отдельное спасибо :)
И вопрос. Стоит ли включать столбец Quan в индекс, если по нему НЕ будет производиться выборка в будущем, он используется только внутри агрегата для подсчета остатков на момент времени?
...
Рейтинг: 0 / 0
Переписать запрос для использования в индексированном представлении
    #39840718
invm
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Alexey30Стоит ли включать столбец Quan в индекс, если по нему НЕ будет производиться выборка в будущем, он используется только внутри агрегата для подсчета остатков на момент времени?В данном случае в ключ индекса включены все столбцы из предложения group by для обеспечения его уникальности.
...
Рейтинг: 0 / 0
17 сообщений из 17, страница 1 из 1
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / Переписать запрос для использования в индексированном представлении
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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