Задача:
Написать процедуру которая принемает параметр (Изделие item) и производит его разузловку (строит дерево вхождений)
Вопросы:
1. Как это делается ?
2. Есть ли смысл в переходе на нововведения ?
Парктика.
[SQL Server 2000] Что было в начале....
CREATE PROCEDURE [dbo].[MyProcSp] (@item NVARCHAR(255) = NULL)
AS
DECLARE @Col DECIMAL(10,5)
DECLARE @NowStartDate DATETIME
DECLARE @Item1 NVARCHAR(50)
DECLARE @pos SMALLINT
SET @NowStartDate = GETDATE()
IF OBJECT_ID('tempdb..#ItmTableTmp') IS NULL
BEGIN
CREATE TABLE #ItmTableTmp (item nvarchar(50)
, itemSub nvarchar(50)
, u_m nvarchar(3)
, Qty decimal(10,5)
, Level int
, P_M_T_Code nvarchar (1))
END
INSERT INTO #RET_STItem
SELECT @item, jm.item, i1.u_m, jm.matl_qty, @pos, i1.p_m_t_code
FROM item i
INNER JOIN job j ON (i.item=j.item) AND (i.job = j.job) AND (i.suffix = j.suffix) AND (j.type = 'S')
INNER JOIN jobmatl jm ON (jm.job = j.job) AND (jm.suffix = j.suffix)
INNER JOIN item i1 ON i1.item = jm.item
WHERE i.item = @item
AND jm.alt_group_rank = 0
ORDER BY jm.sequence
DECLARE @itemSub NVARCHAR(255)
DECLARE @posNext SMALLINT
DECLARE @p_m_t_code NVARCHAR(2)
SET @posNext=@pos+1
DECLARE c_cur CURSOR LOCAL STATIC FOR SELECT itemsub, qtyBase, p_m_t_code FROM #RET_STItem WHERE Level=@Pos and item=@item
OPEN c_cur
FETCH NEXT FROM c_cur INTO @itemSub,@Col,@p_m_t_code
WHILE @@Fetch_status=0
BEGIN
IF (DATEDIFF(mi, @NowStartDate, GETDATE()) < 31)
BEGIN
IF @p_m_t_code='M' EXEC [DBO].[RET_ShowStructItem1] @itemSub, @posNext,@Col
END
FETCH NEXT FROM c_cur INTO @itemSub,@Col,@p_m_t_code
END
CLOSE c_cur
DEALLOCATE c_cur
SELECT r.item
, i1.description
, r.QtyConst
, level
FROM #RET_STItem r
INNER JOIN item i ON i.item=r.itemsub
INNER JOIN item i1 ON i1.item=r.item
ORDER BY r.level, r.item, r.seq
Альтернативный вариант, написан на SQL Server 2005
CREATE PROCEDURE [dbo].[MyProcSp] (@item NVARCHAR(255) = NULL)
AS
DECLARE @pos SMALLINT
WITH RptOut (item, itemSub, u_m, Qty, Level, P_M_T_Code)
AS
(
-- Оригинал
SELECT i.item
, jm.item
, i1.u_m
, jm.qty
, rp.Level + 1
, i1.p_m_t_code
FROM item i
INNER JOIN job j ON (i.item=j.item) and (i.job=j.job) and (i.suffix=j.suffix) and (j.type='S')
INNER JOIN jobmatl jm ON (jm.job=j.job) and (jm.suffix=j.suffix)
INNER JOIN item i1 ON i1.item=jm.item
WHERE i.item=@item
AND jm.alt_group_rank = 0
UNION ALL
-- Рекурсия
SELECT i.item
, jm.item
, i1.u_m
, jm.qty
, rp.Level + 1
, i1.p_m_t_code
FROM item i
INNER JOIN job j ON (i.item=j.item) and (i.job=j.job) and (i.suffix=j.suffix) and (j.type='S')
INNER JOIN jobmatl jm ON (jm.job=j.job) and (jm.suffix=j.suffix)
INNER JOIN item i1 ON i1.item=jm.item
INNER JOIN RptOut rp ON rp.itemSub = i.item
WHERE jm.alt_group_rank = 0
)
SELECT * FROM RptOut
Как это делается показано выше, а вот есть ли смысл.....
Проводил тест на статичной базе (в базе работал только 1 пользователь) по изделию в который входит более 1500 вхождений.
Старые наработки [CURSOR] => выполнилось за 326 мс
Новый вариант [WITH] => выполнилось за 216 мс
В среднем прирост получается 33%
Статичной базе сильно незаметна выгода, а в активно рабочей базе прирост будет ощутим.
P.S.: Первый код (CURSOR) взят с рабочей базы и был изсправлен, в связи с этим
некоторые данные не совподают ;)
Со временем поправлю
Практика показала что если использовать WITH то Таблица которую он создает, может использоватся толька 1 раз. Либо ее необходимо поместить во временную таблюцу.
Комментариев нет:
Отправить комментарий