|
|
|
Триггер DELETE в случае группового удаления данных
|
|||
|---|---|---|---|
|
#18+
Имеется триггерная функция. Она не только производит удаление, но и еще манипулирует данными таблицы. При удалении одной записи - все работает прекрасно. Как только приходит запрос на удаление набора записей начинается непонятное. Я так понял, что при поступлении на удаление набора строк, Postgres, вначале, выполняет для каждой строки всего набора секцию before. Затем, снова поочередно для каждой строки из набора, удаление. Ну и в конце, аналогично, секцию after. Первый вопрос - верно ли мое предположение? Второй, если "да", нет ли способа определения триггера (триггерной функции) на удаления, при котором обрабатывается каждая запись из набора на удаления поочередно? (то есть берется строка... к ней применяется before, удаление, after... берется следующая строка...) Ну и третий вопрос, в догонку... Чем и как отлаживать триггерные функции? На форуме перечитал много подобных веток. Но, во первых, все они старые. Во вторых, нашел только про отладчик под виндовс... (сервер Postgres я запускаю на Убунте в ВиртуалБоксе. Соединяюсь с сервером при помощи pgAdmin3 из OS X) Буду очень благодарен за дельный совет по отладке. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.02.2015, 10:21 |
|
||
|
Триггер DELETE в случае группового удаления данных
|
|||
|---|---|---|---|
|
#18+
... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.02.2015, 10:38 |
|
||
|
Триггер DELETE в случае группового удаления данных
|
|||
|---|---|---|---|
|
#18+
vyegorov, Извиняюсь, сразу не указал сей важный момент. Триггер объявлен именно FOR EACH ROW. И когда был один AFTER. И затем, когда я сделал два, разбил функцию на два триггера - BEFORE и AFTER (собственно, так я понял, что могу предположить вышеописанную проблему при групповом удалении. часть багов это решило, но один остался, поэтому и пишу здесь) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.02.2015, 10:46 |
|
||
|
Триггер DELETE в случае группового удаления данных
|
|||
|---|---|---|---|
|
#18+
EvgIqПри удалении одной записи - все работает прекрасно. Как только приходит запрос на удаление набора записей начинается непонятное. Все же, в чем собственно проблема? И приведите определения таблиц, триггеров и, по возможности, функций. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.02.2015, 12:43 |
|
||
|
Триггер DELETE в случае группового удаления данных
|
|||
|---|---|---|---|
|
#18+
vyegorov, Тут получится много, но раз уж начал :) В общем пытаюсь реализовать систему хранения структуры "дерево", почитать о чем речь можно здесь: http://habrahabr.ru/post/166699/ Я являюсь автором этой статьи. На данный момент пытаюсь реализовать работу с деревом на сервере. Все вроде работает кроме удаления (и я подозреваю, что такая же история будет и при групповом перемещении... но это маловероятная операция) При удалении записи идет проверка на "дырки", которые могут быть вызваны удалением. Их пытаюсь "заделать" перемещением крайне правого элемента на место "дырки" Когда удаляешь одну запись работает прекрасно. Когда удаляешь группу с Код: plaintext Вот код, может кого и заинтересует :) А может кто-то и подскажет что я делаю неправильно (не судите строго, это типо мое хобби, в коде много корявостей, и всяких казалось бы лишних вещей, связанных с тем что правлю его еще походу) Код: plsql 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. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58. 59. 60. 61. 62. 63. 64. 65. 66. 67. 68. 69. 70. 71. 72. 73. 74. 75. 76. 77. 78. 79. 80. 81. 82. 83. 84. 85. 86. 87. 88. 89. 90. 91. 92. 93. 94. 95. 96. 97. 98. 99. 100. 101. 102. 103. 104. 105. 106. 107. 108. 109. 110. 111. 112. 113. 114. 115. 116. 117. 118. 119. 120. 121. 122. 123. 124. 125. 126. 127. 128. 129. 130. 131. 132. 133. 134. 135. 136. 137. 138. 139. 140. 141. 142. 143. 144. 145. 146. 147. 148. 149. 150. 151. 152. 153. 154. 155. 156. 157. 158. 159. 160. 161. 162. 163. 164. 165. 166. 167. 168. 169. 170. 171. 172. 173. 174. 175. 176. 177. 178. 179. 180. 181. 182. 183. 184. 185. 186. 187. 188. 189. 190. 191. 192. 193. 194. 195. 196. 197. 198. 199. 200. 201. 202. 203. 204. 205. 206. 207. 208. 209. 210. 211. 212. 213. 214. 215. 216. 217. 218. 219. 220. 221. 222. 223. 224. 225. 226. 227. 228. 229. 230. 231. 232. 233. 234. 235. 236. 237. 238. 239. 240. 241. 242. 243. 244. 245. 246. 247. 248. 249. 250. 251. 252. 253. 254. 255. 256. 257. 258. 259. 260. 261. 262. 263. 264. 265. 266. 267. 268. 269. 270. 271. 272. 273. 274. 275. 276. 277. 278. 279. 280. 281. 282. 283. 284. 285. 286. 287. 288. 289. 290. 291. 292. 293. 294. 295. 296. 297. 298. 299. 300. 301. 302. 303. 304. 305. 306. 307. 308. 309. 310. 311. 312. 313. 314. 315. 316. 317. 318. 319. 320. 321. 322. 323. 324. 325. 326. 327. 328. 329. 330. 331. 332. 333. 334. 335. 336. 337. 338. 339. 340. 341. 342. 343. 344. 345. 346. 347. 348. 349. 350. 351. 352. 353. 354. 355. 356. 357. 358. 359. 360. 361. 362. 363. 364. 365. 366. 367. 368. 369. 370. 371. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.02.2015, 13:01 |
|
||
|
Триггер DELETE в случае группового удаления данных
|
|||
|---|---|---|---|
|
#18+
в посте выше есть недосказанность: Когда удаляешь одну запись работает прекрасно. Когда удаляешь группу с count_childs=0 происходит непонятное поведение. извиняюсь... ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.02.2015, 13:04 |
|
||
|
Триггер DELETE в случае группового удаления данных
|
|||
|---|---|---|---|
|
#18+
EvgIqв посте выше есть недосказанность: Когда удаляешь одну запись работает прекрасно. Когда удаляешь группу с count_childs=0 происходит непонятное поведение. извиняюсь... Скажите словами в чем проявляется “непонятное поведение”? Вокруг да около ходите, а в чем проблема не говорите. И пример приведите для корректного случая и для "непонятного", будет проще. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.02.2015, 14:20 |
|
||
|
Триггер DELETE в случае группового удаления данных
|
|||
|---|---|---|---|
|
#18+
vyegorov, На словах довольно трудно объяснить. При удалении элемента, если он не последний у родителя, в последовательности детей получается "дырка". Ее наличие недопустимо. Поэтому на ее место перемещаю крайне правого ребенка у того же родителя. Соответсвенно происходит пересчет этого ребенка и его поддерева согласно нового места (на место "дырки"). Одиночное перемещение работает. То есть имеем, например, последовательность детей у одного родителя (X1,X2,Y1..Yn), где X - Элементы без детей, с count_childs=0, (их можно удалить), а Y элементы с детьми, которые, в свою очередь содержат подобную же последовательность детей. Если удалить один Х из любого места, Yn нормально "встанет", со всем своим поддеревом, на место удаленного Х, произойдет пересчет id как самого Yn (он станет равным Х), так и всех его детей. Но если удалять одним запросом все элементы Х (с count_childs=0) на всех уровнях (а это допустимо при такой структуре дерева, и ингода может быть удобно), то нормального пересчета (сворачивания дерева) не происходит, и id у потомков, перемещаемого на место "дырки" элемента, получаются некорректные. Точнее там запускается серия перемещений, так как "дырок" в этом случае образуется много. Сегодня вечером сделаю подробный пример со скринами :) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.02.2015, 14:59 |
|
||
|
Триггер DELETE в случае группового удаления данных
|
|||
|---|---|---|---|
|
#18+
EvgIqв посте выше есть недосказанность: Когда удаляешь одну запись работает прекрасно. Когда удаляешь группу с count_childs=0 происходит непонятное поведение. извиняюсь... мне думается, что пост выше надо пересказать в двух словах, а то проматывать колёсиком лень, не то что ещё прочитать и вдуматься и разобрать на запчасти эту длинную мысль. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.02.2015, 15:40 |
|
||
|
Триггер DELETE в случае группового удаления данных
|
|||
|---|---|---|---|
|
#18+
alex564657498765453, а зачем тогда Вы здесь? остроумием меряться? так я не школьник уже, но ответить смогу не сумлевайтесь ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.02.2015, 15:51 |
|
||
|
Триггер DELETE в случае группового удаления данных
|
|||
|---|---|---|---|
|
#18+
EvgIq, У меня есть ощущение, что проблема не в триггерах, а в алгоритме. Нужно вникнуть. Предоставьте пожалуйста: 1. Структуру таблиц 2. Триггера и функции (уже есть) 3. Очень небольшие тестовые данные 4. Для этих данных, покажите что конкретно не работает и как это воспроизвести. 5. Покажите, как бы вы хотели, чтобы это работало. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.02.2015, 16:16 |
|
||
|
Триггер DELETE в случае группового удаления данных
|
|||
|---|---|---|---|
|
#18+
vyegorov, - Таблица в листинге есть - В функции fill_emp поменял несколько строк, начиная с 21-й: Код: plsql 1. 2. 3. 4. 5. 6. 7. 8. 9. так как выяснил (с помощью закомментированного райса), что если считать максимально правого ребенка на основе количество детей у родителя, получается неверный результат (конкретно в этом примере - 0 вместо 64). Именно это и навело меня на мысль, изложенную в самом верху. Теперь по остальным Вашим, совершенно справедливым, замечаниям: 1. Для теста, в нижепреведенных функциях RETURN'ы должны быть такие (размерность дерева): Код: plsql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 2. Руками вносим первый элемент, корень дерева: id = -128 lvl = 0 count_childs =0 nm - само заполнится значением id при создании parent_id = -128 3. Заполняем дерево, каждый раз выбирая родителя с максимальным id на предыдущем уровне, делаем это 3 раза (создаем 3 уровня, для демонстрации бага хватит) 4. Имеем исходное дерево http://itmag.es/6fq7Y оно же в админе Django http://itmag.es/6xOz5 5. Сначала пример нормальной работы. Удаляем один элемент -64 Результат - http://itmag.es/34b7r в админке - http://itmag.es/9UyH Это пример нормальной работы. Дети/уровни/коды - все как надо. Первоначальный элемент (-64) удалился, получилась "дырка. На его место переместился элемент бывший ранее (64) со всеми его детьми. 6. Снова вернемся к исходному дереву, но уже удалим все элемент которые не имеют детей: http://itmag.es/6KB12 http://itmag.es/1GnmO 7. Получилось такое безобразие: http://itmag.es/6aOqz http://itmag.es/3jzQ7 А должно быть так: http://itmag.es/5itRR То есть, элемент 64 как и положено стал (-64), но вот его единственный ребенок должен быть с номером (-48) а не (-16). Если добавить уровней и элементов, ситуация становится еще запутаннее. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.02.2015, 17:48 |
|
||
|
Триггер DELETE в случае группового удаления данных
|
|||
|---|---|---|---|
|
#18+
EvgIq, Несколько замечаний: 1. Функции `const_ch` и `const_lv` лучше сделать как `LANGUAGE sql`, они тогда будут "прозрачны" для планировщика; 2. Также их стоит определить как `IMMUTABLE`; 3. Правильно не `childs`, а `children` (это так, придраться). По существу. Создал новую базу. Создал схему (все, что было заявлено). Ничего не могу вставить в таблицу, получаю: Код: sql 1. 2. 3. 4. Что я делаю не так. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.02.2015, 18:49 |
|
||
|
Триггер DELETE в случае группового удаления данных
|
|||
|---|---|---|---|
|
#18+
vyegorov, вбивайте в id цифру ноль (оно потом станет как положено), а в parent_id уже только существующего родителя, на основании его вычислится id. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.02.2015, 20:12 |
|
||
|
Триггер DELETE в случае группового удаления данных
|
|||
|---|---|---|---|
|
#18+
EvgIq, Я пробовал: Код: sql 1. 2. 3. Та же ошибка. Что-то `new_id_board()` не фурычит у вас. Вы могли бы не писать "вбивайте", а привести скрипт, который на пустой базе позволит воспроизвести вашу проблему. Пока я только отладкой занят. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.02.2015, 20:36 |
|
||
|
Триггер DELETE в случае группового удаления данных
|
|||
|---|---|---|---|
|
#18+
vyegorov, я в pgAdmin вбиваю, или в админке Django, все работает ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.02.2015, 20:42 |
|
||
|
Триггер DELETE в случае группового удаления данных
|
|||
|---|---|---|---|
|
#18+
Вы parent_id ставьте существующий. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.02.2015, 21:03 |
|
||
|
Триггер DELETE в случае группового удаления данных
|
|||
|---|---|---|---|
|
#18+
Да, перед первой вставкой, (-128,0,0,0,-128) триггеры отключите. Из-за этого может быть ошибка. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.02.2015, 21:34 |
|
||
|
Триггер DELETE в случае группового удаления данных
|
|||
|---|---|---|---|
|
#18+
Вобщем тут при групповом удалении возникают коллизии. Подгруппа уже перенесена, а со старого места пытаюсь удалить. Хотя смущает, что количество оставшихся элементов в "свернувшемся" дереве правильное, и связанность дерево не потеряло... С помощью райсов выяснил, что как ни указывай порядок удаляемых элементов в запросе DELETE FROM xxx WHERE id IN (5, 1, 3, 6...), удалятся они будут всё равно по возрастанию - (1, 3, 5, 6...). Может на это влияет то, что id - первичный ключ. Вероятно всё бы заработало как надо, если бы можно было указать порядок удаления от Большего к Меньшему. Тогда дерево должно сворачиваться корректно. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 21.02.2015, 01:20 |
|
||
|
Триггер DELETE в случае группового удаления данных
|
|||
|---|---|---|---|
|
#18+
EvgIq, Так заверните DELETE в цикл, и будет вам удаление в правильном порядке. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 21.02.2015, 01:38 |
|
||
|
Триггер DELETE в случае группового удаления данных
|
|||
|---|---|---|---|
|
#18+
Ы, Если Вы про то, что удалять по одной строке с клиентов, все верно, так работать будет, я написал это в самом первом сообщении. Но хотелось бы, конечно, решение на сервере. Если не найду способа, при групповом удалении, выбирать данные в обратном порядке, то переверну само дерево :) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 21.02.2015, 09:07 |
|
||
|
Триггер DELETE в случае группового удаления данных
|
|||
|---|---|---|---|
|
#18+
EvgIqПри удалении элемента, если он не последний у родителя, в последовательности детей получается "дырка". Ее наличие недопустимо. В морг. Откажитесь от этого бессмысленного требования, именно оно делает Вам проблемы. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 21.02.2015, 15:06 |
|
||
|
Триггер DELETE в случае группового удаления данных
|
|||
|---|---|---|---|
|
#18+
Dimitry Sibiryakov, Сама структура дерева такая. Без "дырок" никак не получится. Отказываться я не буду уже, так как всё, кроме группового удаления id (и, возможно группового переноса, но это требуется очень редко, то есть можно тупо запретить переносить по нескольку узлов за раз), работает прекрасно. Решить же баг с групповым удалением можно: 1. Как то заставить Postgresql при групповом удалении брать элементы в обратном порядке если нельзя, то: 2. PRIMARY KEY DESC (в обратной сортировке) если нельзя, то 3. Отказаться от PRIMARY KEY и сделать уникальный индекс DESC (но это ркшкние мне не нравится, хотя может кого-то и устроит, в принципе все так же будет работать) И, наконец, что сработает 100%% - "Перевернуть" дерево. То есть id вычислять в убывающем порядке. Тогда сворачивание дерева будет происходить корректно. И это решение самое простое и интересное, ведь id это всего лишь цифры :) Зато в дереве, с такой структурой, я могу: за один запрос выбирать всех Родителей, за один запрос выбирать всех детей (вообще всех или просто на определенном уровне/уровнях). Получился этакий "Materialized Path" но в типе int со всеми вытекающими :) Да, есть ограничения по размерности дерева. Но, допустим, мне 8х255 хватит :) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 21.02.2015, 21:08 |
|
||
|
Триггер DELETE в случае группового удаления данных
|
|||
|---|---|---|---|
|
#18+
EvgIq, Да, хочу уточнить, что решения 2 и 3 призваны побороть проблему группового удаления id в прямой сортировке. Но не факт что помогут. Это просто мое предположение, что групповое удаление происходит в порядке индекса поля. Можно так же, при удалении/перемещении, если получается "дырка", то не уменьшать количество детей у Родителя. Тогда вычисления нового id на этом уровне будет происходить корректно, структура дерева не порушится. Но... будет попусту расходоваться id - они же "пропадут". А в условиях ограничения размерности дерева это ценный ресурс. Конечно, можно предусмотреть возможность "возвращать" неиспользуемые id для новых элементов. Тут подумать надо, это тоже интересно :) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 21.02.2015, 21:28 |
|
||
|
Триггер DELETE в случае группового удаления данных
|
|||
|---|---|---|---|
|
#18+
Dimitry SibiryakovEvgIqПри удалении элемента, если он не последний у родителя, в последовательности детей получается "дырка". Ее наличие недопустимо. В морг. Откажитесь от этого бессмысленного требования, именно оно делает Вам проблемы. да он по ходу упоротый ранняя весна, обострение т.ч. не мешайте, а помогите советом 2ТС г-н евгений, женя (надеюсь, не палыч), зря вы в версионнике записи кучками двигаете, особо в таком, как postgresl, у вас всё от этого опухнет и отвалится. и индесы, индексы не в одни ворота не пройдут. вам бы блокировочник типа масдай-скл, там есть триггера на стейтменты, где все ваши удаленные записи можно сортировать в deleted.* . а главное -- ничто не пухнет при вашем подходе. т.е. ваш подход -- вот именно для блокировочников подойдёт -- им уже хуже всё равно не будет -- куда уж хуже, когда ты блокировочник. тут и женя, надеюсь не павлович, и тот ничего не испортит. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 22.02.2015, 05:53 |
|
||
|
|

start [/forum/topic.php?fid=53&msg=38884888&tid=1998151]: |
0ms |
get settings: |
8ms |
get forum list: |
20ms |
check forum access: |
4ms |
check topic access: |
4ms |
track hit: |
37ms |
get topic data: |
12ms |
get forum data: |
3ms |
get page messages: |
95ms |
get tp. blocked users: |
2ms |
| others: | 241ms |
| total: | 426ms |

| 0 / 0 |
