Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / Переписать запрос для использования в индексированном представлении / 17 сообщений из 17, страница 1 из 1
22.07.2019, 18:35
    #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
22.07.2019, 18:50
    #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
22.07.2019, 19:04
    #39840142
Alexey30
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Переписать запрос для использования в индексированном представлении
Еще один вариант - это разнести на два события с одинаковой датой: первое будет ввод (с двумя SKU), второе - вывод - с одним.
Это тогда решит все проблемы с индексированной вьюхой, но будет избыточность и как-то не очень красиво это.
...
Рейтинг: 0 / 0
23.07.2019, 11:14
    #39840369
Владислав Колосов
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Переписать запрос для использования в индексированном представлении
Alexey30,

без наборов данных непонятно - что на входе и что надо получить на выходе.
...
Рейтинг: 0 / 0
23.07.2019, 11:54
    #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
23.07.2019, 12:13
    #39840418
Yasha123
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Переписать запрос для использования в индексированном представлении
если так уж хочется имитировать индексированное представление,
сами храните и поддерживайте в отдельной таблице свои MIN(SKU), MAX(SKU).
сервер это не делает по простой причине:
если в вашей таблицы проайпэйтит строку, то пересчитывать COUNT_BIG(*) ему не надо:
счетчик просто не изменится
(при вставке строки увеличится, при удалении уменьшится)
а как, простите, пересчитать MIN и MAX, не сканируя всю таблицу?
может, вы как раз своим апдэйтом истребили предыдущий MIN/MAX?
...
Рейтинг: 0 / 0
23.07.2019, 13:45
    #39840476
Владислав Колосов
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Переписать запрос для использования в индексированном представлении
Alexey30,

от сортировка Вы никуда не уйдёте. Для быстрой выборки вам надо создать витрину, которая будет обновлять min/max при изменениях исходных таблиц. Всегда жертвуешь или скоростью или объёмом хранения.
...
Рейтинг: 0 / 0
23.07.2019, 14:40
    #39840505
uaggster
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Переписать запрос для использования в индексированном представлении
Alexey30, Просто разделите ваш запрос на 2 представления.
В одном, индексированном, храните исходные данные, а второе, с группировками, мин и макс - сделайте обычным.
Ну, т.е. если весь запрос нельзя сделать индексированным представлением, сделайте максимально возможную заготовку, и обычное представление, его использующее.
...
Рейтинг: 0 / 0
23.07.2019, 15:19
    #39840544
Yasha123
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Переписать запрос для использования в индексированном представлении
uaggsterAlexey30, Просто разделите ваш запрос на 2 представления.
В одном, индексированном, храните исходные данные, а второе, с группировками, мин и макс - сделайте обычным.
Ну, т.е. если весь запрос нельзя сделать индексированным представлением, сделайте максимально возможную заготовку, и обычное представление, его использующее.
смысл сего действа в чем?
индексированное представление не пересчитывает агрегаты типа count()
при обновлении таблиц.
а если их все равно придется пересчитывать в вашем "просто представлении" (скан + сорт),
то зачем весь этот огород?
...
Рейтинг: 0 / 0
23.07.2019, 16:38
    #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
23.07.2019, 16:41
    #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
23.07.2019, 16:47
    #39840632
Yasha123
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Переписать запрос для использования в индексированном представлении
uaggsterДаже по вертикально суженной выборке - агрегаты будут быстрее считаться, в отличие от исходных "широких таблиц".
И потом, columnstore можно и поверх индексированного представления создать

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

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

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

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

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

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


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