Переключение на Главную Страницу Страницы: 1 2 [3]  ОтправитьПечать
Очень популярная тема (более 25 ответов) Быстрая проверка вхождения в группу справочника (число прочтений - 26805 )
novichek
Экс-Участник


Re: Быстрая проверка вхождения в группу справочника
Ответ #30 - 26. Декабря 2009 :: 04:37
Печать  
Апну тему Улыбка
Вскрылся тут один ньюанс с приведенными выше триггерами для случая УРБД. Ситуация:
н.р. элемент справочника лежал в корне (не имел родителя)
В перефирийной базе создали новую группу и поместили в нее этот элемент.
Что делает 1с по приходу обмена:
1. удаляет элемент.
2. создает его заново с таким же идом и выставленной принадлежностью группе (еще не существующей)
3. создает группу.

соответственно на п.2 у триггера вставки сносит крышу и он начинает ошалело инсертить в доп табличку... короче зацикливается. "Расциклить" его не проблема, но вот как бы так корректно эту ситуацию побороть, чтобы после каждого обмена не перестраивать все дерево?
  
Наверх
 
IP записан
 
novichek
Экс-Участник


Re: Быстрая проверка вхождения в группу справочника
Ответ #31 - 29. Декабря 2009 :: 03:22
Печать  
Что-то никакой активности Печаль . Либо у всех справочники небольшие, либо УРБД никто не пользует. В общем в моем случае пока остановился на следующем:
Во-первых, немного изменил триггер, который срабатывает на добавление элемента:
Код
Выбрать все
		WHILE @ParentID != $ПустойИД
		BEGIN
			INSERT INTO "+ИмяТаблицыДерева+" (ID, ParentID) VALUES (@ID, @ParentID)
			Set @ParentID = (SELECT ParentID FROM "+ИмяТаблицы+" WHERE ID = @ParentID)
			Set @ParentID = IsNull(@ParentID,$ПустойИД)
		END

		If @ParentID != $ПустойИД
		BEGIN
			INSERT INTO "+ИмяТаблицыДерева+" (ID, ParentID) VALUES (@ID, @ParentID)
		END

		If @IsFolder = 1
		BEGIN
		--для свежедобавленной группы проверим, может уже есть элементы ей принадлежащие?
		--(такое м.б. во время обмена УРБД). В этом случае лучше потом перестроить все дерево (сделаем себе "заметку")
			If Exists (Select id From "+ИмяТаблицы+" WHERE ParentID = @ID)
			BEGIN
				INSERT INTO "+ИмяТаблицыДерева+" (ID, ParentID) VALUES ($ПустойИД, $ПустойИД)
			END
		END
 


Как видно, добавилась проверка в цикле что найденный элемент не NULL и если для добавляемой группы найдена ссылка на нее, то добавляем в таблицу "сигнальную" строку с пустыми идами, которая говорит нам что надо бы все "дерево" перестроить.

Затем, н.р. в ПриНачалеРаботыСистемы смотрим, если такой элемент есть, то обновим все дерево. Н.р. вот таким запросом:
Код
Выбрать все
	Set NoCount On
	Declare @Count int

	truncate table "+ИмяТаблицыДерева+"

	--убираем индексы, чтобы сократить время добавления записей в таблицу
	IF EXISTS (SELECT name FROM sysindexes WHERE name = 'IX_Дерево_"+ВидСправочника+"_ID')
		DROP INDEX "+ИмяТаблицыДерева+".IX_Дерево_"+ВидСправочника+"_ID

	IF EXISTS (SELECT name FROM sysindexes WHERE name = 'IX_Дерево_"+ВидСправочника+"_ParentID')
		DROP INDEX "+ИмяТаблицыДерева+".IX_Дерево_"+ВидСправочника+"_ParentID

	--выбираем все группы и рассчитаем с помощью функции их уровни
	Select id, parentid as parent, dbo.fn_Уровень_"+ВидСправочника+"(id) level
	Into "+времтаб+"
	From "+ИмяТаблицы+" (NoLock) Where IsFolder = 1

	insert into "+времтаб+" (id,parent,level) values ($ПустойИД,$ПустойИД,0)
	Create index IX1 on "+времтаб+" (id)
	Create index IX2 on "+времтаб+" (level)

	Set @Count = (Select Max(level) From "+времтаб+")

	--добавляем 'детей' последнего уровня
	Insert Into "+ИмяТаблицыДерева+"
	Select id, parentid From "+ИмяТаблицы+" (NoLock) where parentid in
		(Select id from "+времтаб+" where level = @count)

	While @Count > 0
	Begin
		--добавляем 'внуков', 'правнуков' и т.д. для родителей текущего уровня
		Insert Into "+ИмяТаблицыДерева+"
		Select dt.id, wr.parent
		From "+ИмяТаблицыДерева+" dt (NoLock)
		Inner Join "+времтаб+" wr on wr.id = dt.parentid and wr.level = @count

		--добавляем элементы и группы этого уровня (всех подчиненных для верхнего уровня)
	 	Insert Into "+ИмяТаблицыДерева+"
		  Select id, parentid From "+ИмяТаблицы+" (NoLock) where parentid in
	 		(Select id from "+времтаб+" where level = @count-1)

		Set @Count = @Count - 1
	End

	--восстановим индексы
	CREATE  INDEX [IX_Дерево_"+ВидСправочника+"_ID] ON [dbo].[Дерево_"+ВидСправочника+"]([ID]) ON [PRIMARY]
	CREATE  INDEX [IX_Дерево_"+ВидСправочника+"_ParentID] ON [dbo].[Дерево_"+ВидСправочника+"]([ParentID]) ON [PRIMARY]

	Drop table "+времтаб+"
 



функция для получения уровня группы:
Код
Выбрать все
	CREATE   FUNCTION dbo."+ИмяФункции+" (@id char(9))  
	RETURNS tinyint
	BEGIN
		Declare @lev tinyint, @parent char(9)

		Set @parent = @id
		Set @lev = 0
		while @parent != $ПустойИД
		Begin
			Select @parent = ParentId From "+ИмяТаблицы+" Where id = @parent
			Set @lev = @lev + 1
		End

		return  @lev
	END
 


На тестовой базе и обычной машине в качестве сервера, перезаполнение всей таблички занимает около 2 секунд при ~70 тыс. элементах в справочнике
  
Наверх
 
IP записан
 
novichek
Экс-Участник


Re: Быстрая проверка вхождения в группу справочника
Ответ #32 - 29. Декабря 2009 :: 12:51
Печать  
и еще, мне одному кажется что в таком виде триггер update слишком ресурсозатратный? Можно н.р. сделать еще одну табличку и хранить в ней id элемента, ид непосредственного родителя (можно туда же засунуть и уровень элемента) и при апдейте элемента сравнивать, если его родитель не изменился, то ничего не делать.
  
Наверх
 
IP записан
 
HeiHeShang
Full Member
***
Отсутствует


I Love YaBB 2!

Сообщений: 101
Зарегистрирован: 01. Августа 2006
Re: Быстрая проверка вхождения в группу справочника
Ответ #33 - 05. Мая 2010 :: 06:18
Печать  
Добавил я тригеры и теперь 1С вылетает с ошибкой, база занята другим процессом, если судить по открытым процесам, то мой коннект единственный, как от этого избавится непонятно пока
  
Наверх
 
IP записан
 
Z1
God Member
*****
Отсутствует


I Love YaBB 2!

Сообщений: 2906
Местоположение: Москва
Зарегистрирован: 26. Мая 2006
Пол: Мужской
Re: Быстрая проверка вхождения в группу справочника
Ответ #34 - 05. Мая 2010 :: 06:55
Печать  
А как вам идея строить дерево в дополнительной таблице
только из групп ( дерево будет значительно меньше  да и тригерры короче по времени выполнения)
и условие ставить не на ID а на PARENTID
  
Наверх
 
IP записан
 
Z1
God Member
*****
Отсутствует


I Love YaBB 2!

Сообщений: 2906
Местоположение: Москва
Зарегистрирован: 26. Мая 2006
Пол: Мужской
Re: Быстрая проверка вхождения в группу справочника
Ответ #35 - 05. Мая 2010 :: 07:03
Печать  
Цитата:
Апну тему Улыбка
Вскрылся тут один ньюанс с приведенными выше триггерами для случая УРБД. Ситуация:
н.р. элемент справочника лежал в корне (не имел родителя)
В перефирийной базе создали новую группу и поместили в нее этот элемент.
Что делает 1с по приходу обмена:
1. удаляет элемент.
2. создает его заново с таким же идом и выставленной принадлежностью группе (еще не существующей)
3. создает группу.

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

Твоя проблема (ИМХО) полностью решается с помощью #34

Тригер должен реагтровать только на пункт 3 ( изменения для элементов пропускаем )
  
Наверх
 
IP записан
 
HeiHeShang
Full Member
***
Отсутствует


I Love YaBB 2!

Сообщений: 101
Зарегистрирован: 01. Августа 2006
Re: Быстрая проверка вхождения в группу справочника
Ответ #36 - 05. Мая 2010 :: 13:56
Печать  
Я изменения элементов и так не учитываю
  
Наверх
 
IP записан
 
Z1
God Member
*****
Отсутствует


I Love YaBB 2!

Сообщений: 2906
Местоположение: Москва
Зарегистрирован: 26. Мая 2006
Пол: Мужской
Re: Быстрая проверка вхождения в группу справочника
Ответ #37 - 05. Мая 2010 :: 14:14
Печать  
HeiHeShang писал(а) 05. Мая 2010 :: 13:56:
Я изменения элементов и так не учитываю

Тогда приведи все свое что есть (смотри в качестве образца #2)
  
Наверх
 
IP записан
 
HeiHeShang
Full Member
***
Отсутствует


I Love YaBB 2!

Сообщений: 101
Зарегистрирован: 01. Августа 2006
Re: Быстрая проверка вхождения в группу справочника
Ответ #38 - 06. Мая 2010 :: 05:30
Печать  
Код
Выбрать все
CREATE TRIGGER parents_update ON SC84
	AFTER UPDATE
	AS
	DECLARE @ID char(9), @ParentID char(9), @IsFolder tinyint, @Level tinyint

	SELECT @ID = ID, @ParentID = ParentID, @IsFolder = IsFolder
	FROM Inserted

	IF @IsFolder = 1
	BEGIN
		DELETE parents.dbo.Дерево_Родителей
			FROM parents.dbo.Дерево_Родителей
			INNER JOIN (
			SELECT
				Parents.ParentID ParentID,
				Children.ID ID
			FROM
				parents.dbo.Дерево_Родителей Parents
				INNER JOIN parents.dbo.Дерево_Родителей Children ON
					Children.ParentID = Parents.ID
			WHERE
				Parents.ID = @ID
			) Children ON
				Children.ParentID = parents.dbo.Дерево_Родителей.ParentID
				AND Children.ID = parents.dbo.Дерево_Родителей.ID
	END

	DELETE FROM parents.dbo.Дерево_Родителей WHERE ID = @ID

	SET @Level = 0
	WHILE @ParentID <> '     0   '
	BEGIN
		INSERT INTO parents.dbo.Дерево_Родителей (ID, ParentID) VALUES (@ID, @ParentID)

		IF @IsFolder = 1
		BEGIN
			INSERT INTO parents.dbo.Дерево_Родителей
				SELECT DISTINCT SubTree.ID, @ParentID
				FROM parents.dbo.Дерево_Родителей SubTree
				WHERE SubTree.ParentID = @ID

		END

		SELECT @ParentID = ParentID FROM SC84 WHERE ID = @ParentID
		SET @Level = @Level + 1
	END

	UPDATE SC84 SET SP10576 = @Level WHERE ID = @ID


	IF @IsFolder = 1
	BEGIN
		UPDATE SC84 SET SP10576 = (SELECT count(*) FROM parents.dbo.Дерево_Родителей WHERE parents.dbo.Дерево_Родителей.ID = ThisRef.ID)
		FROM SC84 ThisRef
		INNER JOIN parents.dbo.Дерево_Родителей SubTree ON SubTree.ID = ThisRef.ID
		WHERE SubTree.ParentID = @ID
	END
 

  
Наверх
 
IP записан
 
trad
1c++ power user
1c++ donor
1c++ moderator
Отсутствует



Сообщений: 3046
Местоположение: Киров
Зарегистрирован: 23. Мая 2006
Пол: Мужской
Re: Быстрая проверка вхождения в группу справочника
Ответ #39 - 06. Мая 2010 :: 05:35
Печать  
добавь
set nocount on
  

1&&2&&3
Наверх
 
IP записан
 
Переключение на Главную Страницу Страницы: 1 2 [3] 
ОтправитьПечать