powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / Выбор оптимального алгоритма
18 сообщений из 18, страница 1 из 1
Выбор оптимального алгоритма
    #32051913
Фотография ВладимирМ
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Есть ХП в которой производится удаление одной записи таблицы. Стоит задача организовать удаление группы записей из этой же таблицы, удовлетворяющих определенному условию.

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

Какие есть еще варианты и какой из них будет более оптимальным с точки зрения производительности?

Речь идет о SQLS7SP4. Удаляется порядка 10 записей. В исходной таблице порядка 100 тыс записей.
...
Рейтинг: 0 / 0
Выбор оптимального алгоритма
    #32051916
fima
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Можно поподробнее, ничего не понял.
Стоит задача организовать удаление группы записей из этой же таблицы, удовлетворяющих определенному условию
Почему бы не написать
Код: plaintext
delete from таблица where условие

Зачем использовать ХП и что то делать в цикле? Может я Вас не понял...
...
Рейтинг: 0 / 0
Выбор оптимального алгоритма
    #32051920
Kirk
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Переписать процедуру, чтобы она удаляла не одну, а все нужные записи?
...
Рейтинг: 0 / 0
Выбор оптимального алгоритма
    #32051963
lvv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
lvv
Гость
Вспомнил пример из института по поводу решения задачи
задача: нужно выпить чай
решение: набрать чайник воды, вскипятить, налить в кружку заварку, налить кипяток, насыпать сахар, перемешать сахар
задача: нужно выпить чай, в чайнике есть горячая вода
решение: вылить воду, задача сведена уже к решенной
...
Рейтинг: 0 / 0
Выбор оптимального алгоритма
    #32051981
Фотография ВладимирМ
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Подробнее:

Есть таблица TabChild. Она является дочерней по отношению к таблице TabParent. Таблицы связаны по DRI.
При удалении записи из таблицы TabChild следует проверить: является ли эта запись последней дочерней записью для соответствующей записи из таблицы TabParent. Если "Да", то следует удалить и запись из родительской таблицы.

Реализовать это условие через триггер - невозможно. Как следствие - создана ХП usp_DeleteOneChild которая и реализует это условие. Т.е. удаляет одну запись из TabChild и если необходимо удаляет одну запись из TabParent.

Теперь ситуация следующая: мне надо удалить одновременно несколько записей из TabChild. Все удаляемые записи удовлетворяют некоторому условию.

Как это сделать?
...
Рейтинг: 0 / 0
Выбор оптимального алгоритма
    #32051991
Kirk
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
> Реализовать это условие через триггер - невозможно
Уай?

create trigger td_TabChild on TabChild for delete as
delete TabParent where not exists(select top 1 id from TabChild inner join deleted on TabChild.id=deleted.id where TabParent.id=TabChild.parent)

Это несколько в лоб, но не исключено, что быстрее, нежели чем бежать курсором по всем удаленным записям.
...
Рейтинг: 0 / 0
Выбор оптимального алгоритма
    #32051994
Фотография MiCe
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
смотря как нужно....
если важно не блокировать данные то во временную таблицу....
...
Рейтинг: 0 / 0
Выбор оптимального алгоритма
    #32052000
Kirk
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Сорри, я, похоже, бред написал =( джойн там ни к чему. Болею =(
...
Рейтинг: 0 / 0
Выбор оптимального алгоритма
    #32052002
fima
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
А почему бы, в новой процедуре, сначала не удалить записи из TabChild а потом уже из TabParent. А триггер можно в 2000 MSSQL он будет типа instead. Процедура будет быстрее чем курсор или цикл.
...
Рейтинг: 0 / 0
Выбор оптимального алгоритма
    #32052009
Фотография ВладимирМ
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Тогда я что-то не понимая в триггерах.

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

Однако, создал триггер на удаление где написал

CREATE TRIGGER [DeleteINChild] ON [dbo].[TabChild]
FOR DELETE
AS
delete TabParent where TabParentID not in (SELECT TabParentID FROM TabChild)

И это замечательно сработало.

Т.е. что, триггер сначала выполняет соответствующую операцию, и только затем выполняет собственно тело триггера?
...
Рейтинг: 0 / 0
Выбор оптимального алгоритма
    #32052012
lvv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
lvv
Гость
2ВладимирМ
Ну вобщем-то этож MS SQL, да сначала удаляется запись, потом срабатывает триггер, строки которые удалились лежат в deleted. Не хотите чтоб удалялись - ROLLBACK TRAN. Вот вкратце и все
...
Рейтинг: 0 / 0
Выбор оптимального алгоритма
    #32052013
fima
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Да, в MSSQL 7 есть только триггер типа after (после), т.е. сначала удаляет а потом выполняет то что в триггере. В 2000 добавился тип insted (вместо), т.е. удаление не выполняется а выполняется то что в триггере. На мой взгляд, в Вашем случае триггер не нужен, напишите процедуру, где сначала удалите из одной а потом из другой таблицы.
...
Рейтинг: 0 / 0
Выбор оптимального алгоритма
    #32052017
Фотография ВладимирМ
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
lvv
Вот ведь... А я тут мучаюсь :)

fima
Наоборот, в моем случае именно триггер и нужен, а написание процедуры приводит к описанным выше заморочкам. Ведь возможно удаление как по одной записи за раз, так и по нескольким. И что, писать несколько процедур?
Удаление нескольких записей - это следствие удаление из другой родительской таблицы TabParent2 одной записи. В это случае триггер как раз не сработает (в SQLS7 нет каскадного удаления) и приходится писать процедуры.

Всем спасибо. Разобрался.
...
Рейтинг: 0 / 0
Выбор оптимального алгоритма
    #32052059
Фотография Garya
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Garya Привилегированный пользователь
Участник
Если я правильно понял, то стоит задача удалить поддерево, если удаляется узел дерева, причем глубина поддерева заранее неизвестна. Сам решал подобную задачу. Ниже привожу варианты решения в той последовательности, в которой сам их опробовал, указывая их плюсы и минусы.

Вариант 1. Устанавливаешь в свойствах БД возможность запуска рекурсивных триггеров. В триггере на удаление из таблицы MyTable пишешь примерно следующее:
Код: plaintext
1.
2.
3.
4.
Create trigger SomeTrigger on MyTable for delete as
if exists(select * from MyTable T inner join deleted D where T.ParentID=D.ID)
    delete from T
    from MyTable T inner join deleted D
    where T.ParentID=D.ID

Рекурсивный запуск подобного триггера автоматом уничтожит все поддерево. Только не забудь, что в самом начале триггера должно стоять условие выхода из рекурсии (то есть, оператор if, а не что-либо другое), иначе получишь бесконечную рекурсию с сообщением об ошибке превышения максимального количества уровней рекурсивных вызовов. Плюсы такого решения - простота реализации. Минусов гораздо больше. Как только включили возможность запуска рекурсивных триггеров, появляется вероятность возникновения непреднамеренной рекурсии по совокупностям таблиц с триггерами. Придется более тщательно продумывать скрипты всех остальных триггеров, и в некоторых из них исключать нежелаемый повторный запуск принудительной проверкой TRIGGER_NESTLEVEL в самом начале триггера. Это минус номер раз. Минус номер два заключается в низком (по сравнению с другими методами) быстродействием. Снижение быстродействия в основном связано с несколькими негативными моментами. Во-первых, на вычисление условия выхода из рекурсии уходит дополнительное время. Во-вторых, при каждом рекурсивном вызове происходит сохранение контекста (это делает SQL-сервер незримо для нас, но он это делает, и на это уходит приличное количество ресурсов). Во-третьих, на практике обычно в триггеры включается более сложный алгоритм дейтсвий, нежели приведен выше. Если текст триггера емкий - а у меня именно так - и одновременно наличествуют причины, по которым производится перекомпиляция триггера при каждом его запуске (перечисление этих причин - отдельная тема) - а у меня они тоже имеются, то получается, что при уделении поддерева глубиной 10 уровней текст триггера должен перекомпилироваться 10 раз! Результат - работает все это хозяйство не просто тормознуто, а супер-пупер-тормознуто. Поэтому я от такого решения отказался.

Вариант 2. В НЕ рекурсивном триггере на циклах устраивается псевдорекурсивный алгоритм раскраски поддерева с помещением всех выявленных им идентификаторов во временную таблицу или табличную переменную. Когда алгоритм отработает, запускается ОДИН РАЗ delete from..., который удаляет из нужной таблицы записи с вычисленными идентификаторами. Этот вариант уже работает существенно быстрее, но для моего случая и его быстродейтсвие меня не устроило.

Вариант 3. Можно существенно увеличить скорость подобной операции, если циклы вообще не крутить, а на этапе ввода новых записей в таблицу привязывать к каждой записи (с помощью триггера на вставку) схему ее расположения в дереве - то есть, полный путь, начиная от вершины, а не только ссылку на прямого родителя. а) Полный путь можно хранить в виде поля varbinary, в которое помещены сцепленный по порядку слева-направо идентификаторы всех родительских записей. б) Можно полный путь хранить в специальной таблице, в которой заводятся специальные поля - уровень иерархии (или порядковый номер идентификатора в прописываемом пути) и собственно сами идентификаторы. Вообще вариант 3 - что а), что б) - имеет один минус. Его реализаций требует выделения под структуру, в которой хранятся "древесные" пути много места, что может привести к распуханию БД. При этом а) требует пространства меньше, чем б). Если база просто гигантская, и увеличение ее размера крайне нежелательно, то можно ограничиться вариантом а). Если размер БД существенного значения не имеет, для более высокого быстродействия предпочтительнее вариант б). Разница между а) и б) состоит в том, что по варианту а) в любом случае будет отрабатывать, да, всего лишь один (по сравнению с вариантом 1 и 2), но гарантирован table scan, поскольку поддерево отфильтровывается по вычисляемому условию (сравнение подстрок varbinary). Тут никакие индексы заведомо работать не будут. Вараинт б) позволяет завести индексы на иденификаторы вспомогательной таблицы, и их на самом деле можно будет задействовать. Но объем БД вырастет прилично - во-первых, из-за весьма емкой вспомогательной таблицы (число записей которой очень грубо равно квадрату числа записей основной таблицы, поделенному на два), а во-вторых, из-за таких же гигантских индексов по полям этой вспомогательной таблицы.

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

TabParent2 (1)->(N) TabChild (N)<-(1) TabParent

Между TabParent2 и TabParent других связей нет

При удалении записи из TabParent2 необходимо удалить все подчиненные записи из TabChild, а из TabParent запись следует удалять только в том случае, если удаляемая запись из TabChild является последней дочерней записью к соответсвующей записи из TabParent.

Проблема была в том, что удаление может быть как из таблицы TabParent2, так и напрямую из таблицы TabChild.

Я почему-то считал, что триггер на удаление в TabChild со связкой в TabParent не пройдет.

Древовидные структуры я тоже использую, но я просто запретил удалять узел, если у него есть дочернии узлы. В моей задаче это допустимо.
...
Рейтинг: 0 / 0
Выбор оптимального алгоритма
    #32052094
fima
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Я конечно не настаиваю, но почему Вы не хотите использовать процедуру? Я не знаю структуры Ваших данных, но если в TabParent не бывает записей которые не являются родителями для TabChild, то следующий вариант:
1. Удаляем записи из таблицы TabChild которые ссылаются на записи которые нужно удалить из TabParent2
2. Удаляем записи из таблицы TabParent2
3. Удаляем записи из таблицы TabParent которые не имеют потомков в таблице TabChild
Если в TabParent есть записи которые не являются родителями для TabChild и их не надо удалять, то так
1. Во временную таблицу или переменную типа таблица выбираем записи из таблицы TabChild которые ссылаются на записи которые нужно удалить из TabParent2
2. Удаляем записи из таблицы TabChild которые ссылаются на записи которые нужно удалить из TabParent2
3. Удаляем записи из таблицы TabParent2
4. Удаляем записи из таблицы TabParent которые не имеют потомков в таблице TabChild и их ид присутствуют во временной таблице
А триггер можно использовать только если у Вас связи между таблицами, не являются вторичными ключами.
...
Рейтинг: 0 / 0
Выбор оптимального алгоритма
    #32052124
Фотография ВладимирМ
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
fima
Это было бы правильно, если удаление из таблицы TabChild являлось бы исключительно следствием удаления из таблицы TabParent2.
Однако, удаление из таблицы TabChild может происходить и само по себе, напрямую, вне зависимости от удаления в какой-либо другой таблице.

Т.е. надо предусмотреть 2 варианта:
1. Прямое удаление записей из TabChild
2. Удаление записей из TabChild как следствие удаление записи из TabParent2

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

А вот если первую записать как процедуру, то возникает естесственное желание использовать ее внутри второй процедуры. Чем изначально и был вызван вопрос.
...
Рейтинг: 0 / 0
Выбор оптимального алгоритма
    #32052127
fima
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Ну вот выяснили :). А по поводу вызова из одной процедуры другой по циклу, могу сказать, что это удобно с точки зрения программирования, но гораздо медленнее работает.
...
Рейтинг: 0 / 0
18 сообщений из 18, страница 1 из 1
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / Выбор оптимального алгоритма
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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