WordPress Kitchen 2014 - Дмитрий Корельский: Ангулярность WordPress бытияWordCamp Kyiv
От истоков JS MVC фреймворков и до создания WordPress-проектов с использованием Angular.js. Или как одна технология может изменить ваш взгляд на WordPress разработку.
Caching on highload Drupal site - Alexander ShumenkoDrupalCampDN
Рассмотрим создание тегированной системы кеширования сущностей для high load сайта на Drupal. В ходе доклада будут рассмотрены наиболее интересные моменты реализации (построение цепочки тегов) так же рассмотрены проблемы и способы их решения.
WordPress Kitchen 2014 - Дмитрий Корельский: Ангулярность WordPress бытияWordCamp Kyiv
От истоков JS MVC фреймворков и до создания WordPress-проектов с использованием Angular.js. Или как одна технология может изменить ваш взгляд на WordPress разработку.
Caching on highload Drupal site - Alexander ShumenkoDrupalCampDN
Рассмотрим создание тегированной системы кеширования сущностей для high load сайта на Drupal. В ходе доклада будут рассмотрены наиболее интересные моменты реализации (построение цепочки тегов) так же рассмотрены проблемы и способы их решения.
Доклад о разработке (а главное - оптимизации) программы на Perl под Raspberry PI.
Наглядно показывает, что в Perl есть немало возможностей, а также инструментов, которые позволяют делать программы быстрее и эффективнее - используя как преимущества самого языка, так и оптимизацию алгоритма программы.
Исай Руслан выступил с темой “Entity. Возрождение легенды” на Drupal Cafe #18
Видео с презентации вы сможете увидеть, перейдя по ссылке https://youtu.be/JkXuirPcBPE?list=PLtUZRIj1OWYzCGb3OCYMVYqnrJ-EpH0Ot
Лекция #5. Введение в язык программирования Python 3Яковенко Кирилл
Web-программирование
Лекция #5. Введение в язык программирования Python 3
Цикл лекций читается в Омском государственном университете им. Ф.М.Достоевского на факультете компьютерных наук.
Лектор: Яковенко Кирилл Сергеевич.
Кирилл Мавродиев, Intel – Обзор современных возможностей по распараллеливанию...Media Gorod
This document discusses Intel Parallel Studio 2011. It provides an overview of the key components of Intel Parallel Studio 2011, including Intel Parallel Composer, Intel Parallel Advisor, Intel Parallel Inspector, and Intel Parallel Amplifier. Intel Parallel Composer includes optimization tools like the Intel Cilk Plus compiler and array notations for data parallelism. Intel Parallel Advisor provides guidance on designing parallel applications. Intel Parallel Inspector checks for memory and threading errors. Intel Parallel Amplifier tunes application performance.
Доклад о разработке (а главное - оптимизации) программы на Perl под Raspberry PI.
Наглядно показывает, что в Perl есть немало возможностей, а также инструментов, которые позволяют делать программы быстрее и эффективнее - используя как преимущества самого языка, так и оптимизацию алгоритма программы.
Исай Руслан выступил с темой “Entity. Возрождение легенды” на Drupal Cafe #18
Видео с презентации вы сможете увидеть, перейдя по ссылке https://youtu.be/JkXuirPcBPE?list=PLtUZRIj1OWYzCGb3OCYMVYqnrJ-EpH0Ot
Лекция #5. Введение в язык программирования Python 3Яковенко Кирилл
Web-программирование
Лекция #5. Введение в язык программирования Python 3
Цикл лекций читается в Омском государственном университете им. Ф.М.Достоевского на факультете компьютерных наук.
Лектор: Яковенко Кирилл Сергеевич.
Кирилл Мавродиев, Intel – Обзор современных возможностей по распараллеливанию...Media Gorod
This document discusses Intel Parallel Studio 2011. It provides an overview of the key components of Intel Parallel Studio 2011, including Intel Parallel Composer, Intel Parallel Advisor, Intel Parallel Inspector, and Intel Parallel Amplifier. Intel Parallel Composer includes optimization tools like the Intel Cilk Plus compiler and array notations for data parallelism. Intel Parallel Advisor provides guidance on designing parallel applications. Intel Parallel Inspector checks for memory and threading errors. Intel Parallel Amplifier tunes application performance.
Примеры решения типичных задач за рамками ядра Yii2Paul Klimov
Рассмотрим сравнительно сложные, и в то же время, часто возникающие, задачи, для которых ядро Yii не дает готового решения. Посмотрим как из отдельных моделей ActiveRecord собирать единые сущности, и как разбивать большие модели на составляющие. Разберем как правильно сохранять файлы и как сэкономить на обработчиках событий и поведениях
- Интернационализация сущностей в базе данных;
- Обработка “ролей” в реляционных базах данных;
- Работа с файлами;
- Вложенные модели;
- Trait вместо Behavior.
50. Виды наследований 1. Одиночное наследование: id pid id INTEGER id pid id pid pid id pid INTEGER … id pid id pid id pid id pid id pid 1. Множественное наследование: id pid id pid id pid id pid id pid id INTEGER ? id pids id pids pids id pids id pids id ? pid INTEGER[] … id pids id pids id pids id pids id pids Иерархические структуры в реляционных базах данных: Adjacency List (Смежные вершины)
51. Множественное наследование id pid id pid id pid id pid id pid id pids id pids pids id pids id pids id id pids id pids id pids id pids id pids Приведение к одиночному наследованию: id pid id pid pid id pid id pid id pid id pid id pid id pid id pid id pid id pid id pid id pid id Иерархические структуры в реляционных базах данных: Adjacency List (Смежные вершины)
52. Множество деревьев tid id pid id pid tid id pid id pid id pid id pid tid tid tid tid id pid id pid id pid id pid id pid id pid id pid id pid tid tid tid tid tid tid tid tid Tree 1 Tree 2 Trees table (сообщения) Иерархические структуры в реляционных базах данных: Adjacency List (Смежные вершины)
53. Структуры таблиц Множественное наследование: JOIN tree items id INTEGER id INTEGER id INTEGER … pid INTEGER pid INTEGER iid INTEGER tid INTEGER Множество деревьев: WHERE tree trees id INTEGER … Иерархические структуры в реляционных базах данных: Adjacency List (Смежные вершины)
89. Подчиненная ветка;Иерархические структуры в реляционных базах данных: Adjacency List (Смежные вершины) Иерархические структуры в реляционных базах данных: Adjacency List (Смежные вершины)
94. Использование Adjacency List Получение смежных узлов: Родительский узел: SELECT * FROMmy_treeWHERE id = [pid]; Подчиненные узлы: SELECT * FROMmy_treeWHEREpid = [id]; Иерархические структуры в реляционных базах данных: Adjacency List (Смежные вершины)
95. Использование Adjacency List Получение родительской ветви: С использованием JOIN: SELECT * FROMmy_treeAS l4 JOINmy_treeAS l3 ON l3.id = l4.pid JOINmy_treeAS l2 ON l2.id = l3.pid JOINmy_treeAS l1 ON l1.id = l2.pid ... WHERE l4.id = [item.pid]; С использованием UNION: SELECT l1.*, 1 AS level FROMmy_treeAS l1 WHERE l1.id = [item.pid] UNIONSELECT l2.*, 2 AS level FROMmy_treeAS l1 JOINmy_treeAS l2 ON l2.id = l1.pid WHERE l1.id = [item.pid] UNIONSELECT l3.*, 3 AS level FROMmy_treeAS l1 JOINmy_treeAS l2 ON l2.id = l1.pid JOINmy_treeAS l3 ON l3.id = l2.pid WHERE l1.id = [item.pid] ... ORDERBY level DESC; Иерархические структуры в реляционных базах данных: Adjacency List (Смежные вершины)
96. Использование Adjacency List Получение родительской ветви: С использованием WITH RECURSIVE (PostgreSQL 8.4): WITH RECURSIVEparentsAS ( SELECT *, ARRAY[t.id] AS exist, FALSE AS cycle FROMmy_treeAS t WHERE id = [item.pid] UNION ALL SELECT t.*, exist || t.id, t.id = ANY(exist) FROMparentsAS p, my_treeAS t WHERE t.id = p.pid AND NOT cycle ) SELECT * FROMparents WHERE NOT cycle LIMIT[max_deep]; WITH RECURSIVE мы создаем рекурсивный подзапрос parents. Первый запрос рекурсии, в нем указываем точку отсчета. Второй запрос, собственно, рекурсивный запрос. Поле exist - массив уже полученных id, который мы проверяем в поле cycle, что бы не уйти в бесконечную рекурсию. LIMIT ограничивает глубину выборки ветки, так как родитель у узла может быть только лишь один. Иерархические структуры в реляционных базах данных: Adjacency List (Смежные вершины)
97. Использование Adjacency List Получение родительской ветви (на уровне приложения): Рекурсивная функция: ... subparent_recurse { my%params = @_; # Текущая глубина рекурсии $params{deep} ||= 1; # Хеш ранее выбранных узлов $params{exist} ||= {}; # Возвращаем пустой список если превысили максимальную заданную глубину рекурсии return () if$params{deep} && $params{max_deep} && $params{deep} > $params{max_deep}; # делаем запрос к базе данных на поллучение следующего узла my$query = 'SELECT * FROM my_tree WHERE id = ' . $params{pid}; my$sth = $dbh->prepare($query); $sth->execute; my$item = $sth->fetchrow_hashref; $sth->finish; # Объявляем внутренний список узлов – родителей my@parents= (); # Если узел найден и у него явно есть родитель, то if($item&& $item->{pid}) { # Для начала проверим, а не выбирали ли мы уже такой родительский узел return () if$params{exist}->{$item->{pid}}; # Не выбирали, тогда добавляем в хеш $params{exist}->{$item->{id}} = 1; # И вызываем снова рекурсивную функцию @parents = &parent_recurse( pid => $item->{pid}, max_deep => $params{max_deep}, deep => $params{deep} + 1, exist => $params{exist} ); } # Добавлем выбранный узел к массиву, если есть push@parents, $itemif$item; # Возвращаем список выбранных узлов return@parents; } ... my@parents = &parent_recurse(pid => $item->{pid}, max_deep => 2); ... Иерархические структуры в реляционных базах данных: Adjacency List (Смежные вершины)
98. Использование Adjacency List Получение родительской ветви (на уровне приложения): Динамический массив: ... # Объявляем пустой список родителей my@parents= (); # Объявляем хеш уже полученных узлов, и добавляем в него id текущего узла my%exist= ($item->{id} => 1); # Объявляем динамический массив и вносим в него текущий узел my@while = ($item); # Максимальная глубина выборки my$max_deep = 3; # Текущая глубина выборки my$deep = 1; # В цикле отрезаем первый эмемент динамического массива до тех пор пока это возможно while (my$item = shift @while && $deep <= $max_deep) { # Прерываем цикл, если узла явно нет родителя или такого родителя мы уже получали lastif!$item->{pid} || $exist{$item->{pid}}; # Делаем запрос к базе данных my$query = 'SELECT * FROM my_tree WHERE id = ' . $item->{pid}; my$sth = $dbh->prepare($query); $sth->execute; my$parent = $sth->fetchrow_hashref; $sth->finish; # Прерываем цикл, если узел не получили lastunless$parent; # Добавляем узел в массив родителей push@parents, $parent; # Добавляем id узла в хеш полученных узлов $exist{$parent->{id}} = 1; # Добавляем узел в динамический массив push@while, $parent; # Инкрементим текущую глубину $deep++; } ... Иерархические структуры в реляционных базах данных: Adjacency List (Смежные вершины)
99. Использование Adjacency List Получение родительской ветви: Хранимая процедура PostgreSQL: CREATE OR REPLACE FUNCTION "public"."get_parents" ( pid_in INTEGER, deep INTEGER ) RETURNS SETOF "public"."my_tree" AS $body$ DECLARE exist_ids INTEGER[] := ARRAY[0]; -- Для пустого массива плохо работает ALL pid_now INTEGER := pid_in; -- Текущий pid deep_now INTEGER := deep; -- Текущаа глубина itemmy_tree; BEGIN WHILE pid_nowIS NOT NULL AND pid_now > 0 AND pid_now <> ALL (exist_ids) AND(deep_nowIS NULL OR deep_now > 0) LOOP SELECT * INTOitemFROMmy_treeWHEREid = pid_now; IFitem.idIS NULL THENEXIT;END IF; RETURN NEXT item; pid_now := item.pid; exist_ids := exist_ids || item.id; IFdeep_nowIS NOT NULL THEN deep_now := deep_now – 1;END IF; END LOOP; RETURN; END; $body$ LANGUAGE 'plpgsql'; -- Для красоты добавим функцию с одним передаваемым параметром CREATE OR REPLACE FUNCTION "public"."get_parents" ( pid_in INTEGER ) RETURNSSETOF "public"."my_tree" AS $body$ SELECT * FROMget_parents( $1, NULL ); $body$ LANGUAGE'sql'; Иерархические структуры в реляционных базах данных: Adjacency List (Смежные вершины)
100. Использование Adjacency List Получение родительской ветви: Хранимая процедура MySQL: CREATE DEFINER = CURRENT_USER PROCEDURE `get_parents`( IN pid_in INTEGER, IN max_deep INTEGER ) BEGIN DECLAREid_now INTEGER; DECLAREpid_now INTEGER DEFAULT pid_in; DECLARE field1_now TEXT; DECLAREexist TEXT DEFAULT '|'; WHILEpid_now > 0 AND existNOT LIKE CONCAT('%|', pid_now, '|%') AND (max_deepIS NULL OR max_deep > 0) DO SELECT * INTOid_now, pid_now, field1_now FROMmy_tree WHEREid = pid_now; SELECTid_now, pid_now, field1_now; IF (max_deepIS NOT NULL)THEN SETmax_deep = max_deep - 1; END IF; SETexist = CONCAT(exist, id_now, '|'); END WHILE; END; Примечание: Возвращается несколько result set. Иерархические структуры в реляционных базах данных: Adjacency List (Смежные вершины)
101.
102. [item.id] - ID узла от которого производится выборка;
104. [limit] - количество выбираемых строк;Основной особенностью этого запроса является дополнительное поле path, которое практически является Materializedpath, за исключением того, что мы добавляем в него дополнительное поле сортировки текущего узла. Причем защита от зацикливания (поля exist и cycle) локализована в пределах отдельных ветвей, поэтому это хоть и предохранит от бесконечного зацикливания, но позволит повторно выбрать строки, так что будте внимательны. Иерархические структуры в реляционных базах данных: Adjacency List (Смежные вершины)
105. Использование Adjacency List Получение дочерней ветви (на уровне приложения): Рекурсивная функция: ... subchild_recurse { my%params= @_; # Текущая глубина рекурсии $params{deep} ||= 1; # Хеш ранее выбранных узлов $params{exist} ||= {}; # Возвращаем пустой список если превысили максимальную заданную глубину рекурсии return () if$params{deep} && $params{max_deep} && $params{deep} > $params{max_deep}; # Объявляем внутренний список узлов – потомков my@children = (); # делаем запрос к базе данных на получение списка подчиненных узлов my$query = 'SELECT * FROM my_tree WHERE pid = ' . $params{pid} . ($params{order} ? ' ORDER BY ' . $params{order} : ''); my$sth = $dbh->prepare($query); $sth->execute; while (my$item = $sth->fetchrow_hashref) { # Для начала проверим, а не выбирали ли мы уже такой узел next () if$params{exist}->{$item->{id}}; # Не выбирали, тогда добавляем в хеш $params{exist}->{$item->{id}} = 1; # Добавлем выбранный узел к массиву push@children, $item; # Вызываем снова рекурсивную функцию для получения подчиненных узлов текущего узла my@children_deep = &child_recurse( pid => $item->{id}, max_deep => $params{max_deep}, order => $params{order}, deep => $params{deep} + 1, exist => $params{exist},); # Добавляем список подчиненных узлов текущего узла push@children, @children_deep; } $sth->finish; # Возвращаем список выбранных узлов return@children; } my@children = &child_recurse(pid => $item->{id}, max_deep => 5, order => 'id'); ... Иерархические структуры в реляционных базах данных: Adjacency List (Смежные вершины)
106. Использование Adjacency List Получение дочерней ветви (на уровне приложения): Оптимизация выборки: Ввести денормализацию таблицы создав дополнительное поле счетчика потомков. В этом случае можно будет проверять наличие потомков и делать или нет запрос на их получение. Это решение рассмотрено более детально ниже; Производить выборки не построчно, а списочно, для каждого уровня вложенности. Это решение подробно рассмотрим здесь; SELECTchildren.* FROMmy_treeASchildren JOINmy_treeASparentsONparents.id = children.pid WHEREchildren.pid = ANY([parents_array]) ORDER BYparents.[order_field], children.[order_field]; Где: [parents_array] - массив id родительских узлов; [order_field] - поле сортировки; Иерархические структуры в реляционных базах данных: Adjacency List (Смежные вершины)
107. Использование Adjacency List Получение дочерней ветви (на уровне приложения): Динамический массив: ... my$max_deep= 5; my$order= 'field1‘; my$limit= 20; my@children= (); my@while= ($item); my%exist= (); my%indexes= (); my$skew= 0; my$pids= []; my$deep_now= 1; while (my$child= shift@while) { nextif$exist{$child->{id}}; $exist{$child->{id}} = 1; push@$pids, $child->{id}; unless (defined$indexes{$child->{pid} || 'NULL'}) { if ($childne$item) { push@children, $child; $indexes{$child->{id}} = $#children; } } else { splice@children, $indexes{$child->{pid}} + $skew+ 1, 0 , ($child); $indexes{$child->{id}} = $indexes{$child->{pid}} + $skew+ 1; $skew++; } unless ($while[0]) { $skew= 0; $deep_now++; lastif$max_deep&& $deep_now> $max_deep; my$query= 'SELECT children.* FROM my_tree AS children JOIN my_tree AS parents ON parents.id = children.pid WHERE children.pid = ANY(?) ORDER BY parents.’.$order.', children.’.$order.($limit ? ' LIMIT ‘.$limit : ''); my$sth= $dbh->prepare($query); $sth->execute($pids); while (my$child= $sth->fetchrow_hashref) {push@while, $child} $sth->finish; } } ... Иерархические структуры в реляционных базах данных: Adjacency List (Смежные вершины)
108.
109. Денормализация (счетчики и уровень).Иерархические структуры в реляционных базах данных: Adjacency List (Смежные вершины)
110. Управление Adjacency List Контроль подчиненности: Триггер PostgreSQL 8.4 и выше: CREATE OR REPLACE FUNCTION "public"."my_tree_update_trigger" () RETURNStriggerAS $body$ DECLARE tmp_id INTEGER; BEGIN -- Если произошло изменение родителя узла IFNEW.pidIS NOT NULL AND (NEW.pid <> OLD.pidOROLD.pidIS NULL) THEN -- Пытаемся найти в родителькой ветки нового родителя текущий узел WITH RECURSIVE parentsAS ( SELECTt.id, t.pid, ARRAY[t.id] AS exist, FALSE AS cycle FROMmy_treeASt WHEREid = NEW.pid UNION ALL SELECT t.id, t.pid, exist || t.id, t.id = ANY(exist) FROMparentsASp, my_treeASt WHEREt.id = p.pidAND NOT p.cycle ) SELECTidINTOtmp_idFROMparentsWHEREid = NEW.idAND NOT cycleLIMIT 1; -- Узел найден, следовательно родителя назначить не можем IFtmp_idIS NOT NULL THEN RAISE NOTICE 'Нельзя ставить потомком родителя!'; NEW.pid := OLD.pid; END IF; END IF; RETURN NEW; END; $body$ LANGUAGE 'plpgsql'; CREATE TRIGGER "my_tree_update" BEFORE UPDATE ON "public"."my_tree" FOR EACH ROW EXECUTE PROCEDURE "public"."my_tree_update_trigger"(); Иерархические структуры в реляционных базах данных: Adjacency List (Смежные вершины)
111. Управление Adjacency List Контроль подчиненности: Триггер PostgreSQL ниже 8.4: CREATE OR REPLACE FUNCTION "public"."my_tree_update_trigger" () RETURNStriggerAS $body$ DECLARE tmp_id INTEGER; BEGIN -- Если произошло изменение родителя узла IFNEW.pidIS NOT NULL AND (NEW.pid <> OLD.pid OR OLD.pidIS NULL) THEN -- Пытаемся найти в родителькой ветки нового родителя текущий узел SELECT idINTOtmp_idFROMget_parents(NEW.pid) WHEREid = NEW.id LIMIT 1; -- Узел найден, следовательно родителя назначить не можем IFtmp_idIS NOT NULL THEN RAISE NOTICE 'Нельзя ставить потомком родителя!'; NEW.pid := OLD.pid; END IF; END IF; RETURN NEW; END; $body$ LANGUAGE 'plpgsql'; CREATE TRIGGER "my_tree_update" BEFORE UPDATE ON "public"."my_tree" FOR EACH ROW EXECUTE PROCEDURE "public"."my_tree_update_trigger"(); Иерархические структуры в реляционных базах данных: Adjacency List (Смежные вершины)
112. Управление Adjacency List Денормализацияcounter и level: Триггер на INSERT (PostgreSQL): CREATE OR REPLACE FUNCTION "public"."my_tree_insert_trigger" () RETURNStrigger AS $body$ DECLARE parentmy_tree; BEGIN -- Что денормализовано, то ставить вручную нельзя NEW.counter := 0; NEW.level := 0; -- Если определен pid тогда обновляем счетчик родителя IFNEW.pidIS NOT NULL ORNEW.pid > 0 THEN -- Сразу вернем результат обновления родителя -- Финт ушами с CASE при обновлении счетчика из-за того что NULL + 1 = NULL, -- поэтому эти поля лучше сразу делать NOT NULL, а сейчас перестрахуемся UPDATEmy_tree SETcounter = CASE WHEN counterIS NULL THEN 1 ELSEcounter + 1 END WHEREid = NEW.pid RETURNING * INTOparent; -- Проверим существование родителя, без отмены операции IFparent.idIS NULL THEN RAISE NOTICE 'ОШИБКА! Родителя с таким ID нет (%)', NEW; NEW.pid := 0; ELSE -- Устанавливаем значение level для вставляемого узла NEW.level := CASE WHEN parent.levelIS NULL OR parent.level = 0 THEN 1 ELSENEW.level + 1 END; END IF; END IF; RETURN NEW; END; $body$ LANGUAGE 'plpgsql'; CREATE TRIGGER "my_tree_insert" BEFORE INSERT ON "public"."my_tree" FOR EACH ROW EXECUTE PROCEDURE "public"."my_tree_insert_trigger"(); Иерархические структуры в реляционных базах данных: Adjacency List (Смежные вершины)
113. Управление Adjacency List Денормализацияcounter и level: Триггер на UPDATE (PostgreSQL): CREATE OR REPLACE FUNCTION "public"."my_tree_update" ()RETURNStrigger AS $body$ DECLARE parentmy_tree; childmy_tree; level_skew INTEGER; pids INTEGER[]; tmp_pids INTEGER[]; exist_update INTEGER[]; BEGIN -- Опять же для предотвращения сравнения с NULL ставим 0 IFOLD.pidIS NULL THEN OLD.pid := 0; END IF; IFNEW.pidIS NULL THEN NEW.pid := 0; END IF; IFOLD.levelIS NULL THEN OLD.level := 0; END IF; -- Если произошла смена родителя IFNEW.pid <> OLD.pidTHEN -- Уменьшаем счетчик старого родителя если он есть IFOLD.pid > 0 THEN UPDATE my_treeSETcounter = counter - 1 WHEREid = OLD.pid; END IF; -- Увеличиваем счетчик нового родителя если он есть IFNEW.pid > 0 THEN UPDATEmy_treeSETcounter = COALESCE(counter, 0) + 1 WHEREid = NEW.pidRETURNING * INTOparent; -- Проверяем существование родителя IFparent.idIS NULL THEN RAISE NOTICE 'ОШИБКА! Родителя с таким ID нет (%)', NEW; NEW.level := 0; NEW.pid := 0; ELSE -- Если родитель есть то устанавливаем новый уровень узла NEW.level := COALESCE(parent.level, 0) + 1; END IF; ELSE NEW.level := 0; END IF; -- Данные по перемещаемому узлу обновили, теперь следует обновить -- level потомков перемещаемого узла level_skew := NEW.level - OLD.level; ... Иерархические структуры в реляционных базах данных: Adjacency List (Смежные вершины)
114. Управление Adjacency List Денормализацияcounter и level: Триггер на UPDATE (PostgreSQL), продолжение: ... -- Смещение уровня таки есть IFlevel_skew <> 0 THEN pids := ARRAY[NEW.id]; exist_update := ARRAY[NEW.id]; -- Пока есть узлы у которых есть потомки: WHILEpids[1] IS NOT NULL LOOP tmp_pids := ARRAY[NULL]; -- Обновляем всех потомков на уровне FORchildIN UPDATE my_tree SETlevel = level + level_skew WHEREpid = ANY (pids) ANDid <> ALL (exist_update) RETURNING * LOOP -- Поставим защиту для того, что бы невозможно было поставить узел в починение своему потомку IFchild.id = NEW.pidTHEN RAISE EXCEPTION 'Ошибка! Нельзя ставить узел в подчинение потомку! (%)', NEW; RETURN NULL; END IF; -- Если у потомка еще есть потомки, то добавляем его id в список на обновление -- следующего уровня IFchild.counterIS NOT NULL ANDchild.counter > 0 THEN tmp_pids := array_prepend(child.id, tmp_pids); END IF; -- Защита от повторов exist_update := array_append(exist_update, child.id); END LOOP; pids := tmp_pids; END LOOP; END IF; END IF; RETURN NEW; END; $body$ LANGUAGE 'plpgsql'; CREATE TRIGGER "my_tree_update" BEFORE UPDATE ON "public"."my_tree" FOR EACH ROW EXECUTE PROCEDURE "public"."my_tree_update"(); Иерархические структуры в реляционных базах данных: Adjacency List (Смежные вершины)
115. Управление Adjacency List Денормализацияcounter и level: Триггер на DELETE (PostgreSQL) : CREATE OR REPLACE FUNCTION "public"."my_tree_delete_trigger" () RETURNStriggerAS $body$ BEGIN -- Если есть родитель, то обновляем его счетчик IFOLD.pidIS NOT NULL AND OLD.pid > 0 THEN UPDATEmy_tree SETcounter = counter – 1 WHEREid = OLD.pid; END IF; IFcurrent_setting('user_vars.tree_delete') = 'levelup' THEN UPDATEmy_tree SETpid = OLD.pid WHERE pid = OLD.id; ELSIFcurrent_setting('user_vars.tree_delete') = 'root' THEN UPDATEmy_tree SETpid = 0 WHEREpid = OLD.id; ELSE IFOLD.counterIS NOT NULL AND OLD.counter > 0 THEN DELETE FROM my_treeWHEREpid = OLD.id; END IF; END IF; RETURN OLD; END; $body$ LANGUAGE 'plpgsql'; CREATE TRIGGER "my_tree_delete" AFTER DELETE ON "public"."my_tree" FOR EACH ROW EXECUTE PROCEDURE "public"."my_tree_delete_trigger"(); Иерархические структуры в реляционных базах данных: Adjacency List (Смежные вершины)
116. Управление Adjacency List Денормализацияcounter и level: Способы удаления ветвей: 1. Транзакционный: BEGIN; SELECTset_config('user_vars.tree_delete', 'levelup', TRUE); DELETE FROM my_treeWHEREid = [item.id]; COMMIT; 1. Не транзакционный: DELETE FROM my_tree USING ( SELECTset_config('user_vars.tree_delete', 'root', TRUE) ) ASconf WHEREid = [item.id]; Иерархические структуры в реляционных базах данных: Adjacency List (Смежные вершины)
117. Вопросы? Статьи по теме: http://doc.prototypes.ru/database/trees/ Сергей Томулевич Rambler, Москва, 2010 Карикатуры: Сергей Корсун Иерархические структуры в реляционных базах данных: Adjacency List (Смежные вершины)