|
Иерархия в базе данных | ☑ | ||
---|---|---|---|---|
0
Волшебник
модератор
06.03.17
✎
22:17
|
Для отображения иерархии в базе данных часто используют поле "Родитель", которое содержит ID родителя. Например, {ID, name, parent}, где parent - такое же значение как ID.
Для _хранения_ иерархии этого вполне достаточно, но возникают сложности с отображением и выборкой такой иерархии. Уж слишком сложные функции получаются просто для отображения дерева. Ведь нужно посчитать уровень элемента, а значит нужно пробежаться по родителям до корня в цикле. Для вывода дерева часто используется рекурсия, которая может свалиться в бесконечность и вызвать крах приложения и даже отладчика. Есть и другие методы решения этих проблем, например, нарушить нормализацию и завести поле "Родители" (полный путь), содержащее коды всех родителей через слэш. Или ещё более надёжный вариант: создать отдельную таблицу с отношениями между элементами (аналог ClosureTable), которая содержит ID предка и ID потомка любой вложенности в одной записи. Это ускоряет все запросы на выборку подчинённых элементов заданного родителя, но замедляет обновление таблицы. Что посоветуете для элегантного решения проблемы иерархии справочников в контексте разработки мобильного приложения для Android на языке Java, где базой управляет SQLite? |
|||
1
vde69
06.03.17
✎
22:28
|
я так рассуждаю
1. андроид - значит мало памяти 2. оптимизация - на чтение или на запись, скорее на чтение любые дополнительные таблицы/поля - жрут память значит остается классический вариант с родителем либо изменять изначальные условия 1 и 2 |
|||
2
Волшебник
модератор
06.03.17
✎
22:37
|
(1) В любом смартфоне уже 2-3 Гб есть памяти, а скоро будет 4-6. Размер базы данных конкретно для моего приложения не имеет значения. Там будут чисто цифры и тексты (учёт домашних финансов), а всё это мало места занимает (это же не картинки и не видео).
|
|||
3
Неверный Параметр И
06.03.17
✎
22:40
|
||||
4
Неверный Параметр И
06.03.17
✎
22:41
|
Там методы на любой вкус с анализом
|
|||
5
Волшебник
модератор
06.03.17
✎
22:43
|
(3) Ага, спасибо за ссылку. Это путь в правильном направлении.
|
|||
6
Неверный Параметр И
06.03.17
✎
22:43
|
Я бы остановился на классических nested sets
|
|||
7
Волшебник
модератор
06.03.17
✎
22:45
|
(6) Больше интересуют планы запросов и вложенные циклы. Лишь бы не получилось запросов в цикле. Самая страшная страшилка 1С-ников...
|
|||
8
vde69
06.03.17
✎
22:46
|
(2) тогда делай 3 таблицы
1. справочник без групп, у элемента поле родитель (ссылка на вторую таблицу) 2. рубрикатор (справочник групп) 3. связи элементов рубрикатора простое чтение внутри группы - джойн 1+2 построение дерева на форме - 3+2 (тут возможны проблеммы при рекурсии и не однозначных связях) запись элемента - только таб 1 перенос элемента в друг группу - 1+3 перенос группы - таб 3 |
|||
9
Волшебник
модератор
06.03.17
✎
22:49
|
(8) А не слишком ли это круто для простого иерархического справочника? Мне кажется, что даже 2 таблицы уже круто, а ты сразу 3 таблицы зарядил...
|
|||
10
vde69
06.03.17
✎
22:52
|
(9) зато соответствует правилам нормализации - все три таблицы не содержат неиспользуемых полей.
таблица 2. - будет вообще милипусенькая, да и таб 3 то-же не большая |
|||
11
Волшебник
модератор
06.03.17
✎
22:53
|
(10) Можешь привести структуру таблиц для большего пониманиям этого беспредела?...
|
|||
12
Волшебник
модератор
06.03.17
✎
22:56
|
Параллельно я буду приводить свои изыскания на эту тему.
Например, типичная задача: "Выбрать все подчинённые элементы заданного родителя (с учётом вложенности)" реализуется запросом: SELECT * FROM Expenses WHERE guid = "AA1" OR parents LIKE "%AA1%" О, боже! Это же супер-тормоз! Да, в моём случае сработает, но что будем делать с другими случаями? |
|||
13
vde69
06.03.17
✎
22:58
|
таб 1 - Name, ID_P
таб 2 - ID, Name таб 3 - ID_1, ID_2 полное дерево джойнится 1.ID_P = 2.ID 2.ID = 3.ID_1 3.ID_1 = 3.ID_2 |
|||
14
Волшебник
модератор
06.03.17
✎
22:59
|
(13) А что за волшебная фея заполняет таб2 и таб3?
|
|||
15
vde69
06.03.17
✎
23:00
|
(13) + что-то наврал :)
|
|||
16
vde69
06.03.17
✎
23:04
|
может так
таб 1 - Name, ID_P таб 2 - ID, Name, ID_P 1.ID_P = 2.ID 2.ID = 2.ID_P то есть это то же что и в 1с, только разделили на 2 таблицы для того, что бы не было не используемых полей. |
|||
17
Asmody
06.03.17
✎
23:09
|
храни структуру в отдеьном json-файле
|
|||
18
Asmody
06.03.17
✎
23:20
|
Вот https://habrahabr.ru/post/46659/ про разные способы представления иерархии в реляционных базах
|
|||
19
Волшебник
модератор
06.03.17
✎
23:23
|
(18) Хорошая статья. Читаю
|
|||
20
Волшебник
модератор
07.03.17
✎
10:38
|
Временное решение пока такое:
В таблице иерархического справочника есть исходные поля: parent - id родителя, position - число, позиция в пределах группы, и дополнительные поля: folder - путь от корня до вышестоящей папки (по умолчанию "/") level - число, глубина вложенности ordinal - особая строка для сортировки, содержащая позиции и id всех родителей + собственную позицию и id Пример ordinal: /#00001#C25/#00002#AA3/#00001#BF6 где #00001#C25 - папка с ID=C25 и позицией №1 #00002#AA3 - папка AA3 с позицией №2 #00001#BF6 - сам элемент BF6 с позицией №1 В программном коде есть добрая фея, которая заполняет все эти дополнительные реквизиты на основе parent и position. Т.е. при записи элемента справочника прилетает фея и своей волшебной палочкой перенумеровывает все элементы справочника. Запись замедляется, но в итоге запрос вывода дерева с учётом позиции внутри группы становится тривиальным и не требует пост-обработки в программном коде: SELECT *, folder || ID AS FullPath FROM Catalog ORDER BY ordinal ASC |
|||
21
Волшебник
модератор
07.03.17
✎
10:41
|
(20)+ картинко
![]() |
|||
22
Naf2017
07.03.17
✎
13:59
|
вот иерархия как вложенные интервалы http://www.codenet.ru/db/other/trees/
|
|||
23
arsik
гуру
07.03.17
✎
14:04
|
У нас уровень сразу хранится в элементе, как доп поле. Спасает неплохо.
|
|||
24
arsik
гуру
07.03.17
✎
14:06
|
(20) Ты изобрел клюшки?
|
|||
25
Asmody
07.03.17
✎
14:07
|
(24) Всё уже придумано до нас
|
|||
26
Волшебник
модератор
07.03.17
✎
14:08
|
(24) Я не в курсе, что там было в клюшках.
|
|||
27
arsik
гуру
07.03.17
✎
14:21
|
Можно гибрид сделать.
В элементе хранить только родителя, а в группах хранить всю иерархию. |
|||
28
arsik
гуру
07.03.17
✎
14:33
|
Запись ускорится, запрос ненамного замедлится
|
|||
29
Волшебник
модератор
07.03.17
✎
14:34
|
(27) Похоже на химеру
|
|||
30
SanGvin
07.03.17
✎
14:35
|
а если всю иерархию хранить в таблице вида
id элемента, id родителя, уровень Можно одним джойном выбрать всех родителей |
|||
31
Волшебник
модератор
07.03.17
✎
14:40
|
||||
32
SanGvin
07.03.17
✎
14:42
|
имхо самый оптимальный вариант если скорость выборки важнее скорости записи
|
|||
33
Живой Ископаемый
07.03.17
✎
14:42
|
(0) Не иметь для мобильной базы глубину иерархии более 1 уровня.
|
|||
34
Asmody
07.03.17
✎
14:46
|
(33) У него это статьи доходов/расходов. Как по ним агрегацию делать?
|
|||
35
Про100Филя
07.03.17
✎
14:49
|
(0)Однозначно две таблицы. Таблица самих строк и таблица родителей. В таком случае все запросы к скулю станут простыми + легче будет запросом/добавлять удалять строки вместе с вложеными.
|
|||
36
Волшебник
модератор
07.03.17
✎
14:51
|
(34) Можно сделать 2 справочника, подчинённых друг другу, например, группы статей и сами статьи. Тогда вообще без иерархии получится. Кстати, в одной программе так и сделано (Personal Finance от SKM)
|
|||
37
Asmody
07.03.17
✎
14:51
|
(35) Да-да, "простыми". Например, выбрать все записи под родителем 1го уровня. А уровней, ну допустим, 2-3.
|
|||
38
Asmody
07.03.17
✎
14:52
|
(36) Можно операции помечать не статьями, а тегами. И собирать аналитику по тегам.
|
|||
39
Asmody
07.03.17
✎
14:55
|
Например, вы поехали куда-то с целью развлечься и купили там поесть. Тогда помечаешь расход: "путешествия", "развлечения" и "еда".
|
|||
40
Волшебник
модератор
07.03.17
✎
14:55
|
(38) Неплохая идея. И ещё надо обязательно прикрутить корованы, которые можно грабить. И котиков.
|
|||
41
arsik
гуру
07.03.17
✎
14:56
|
(39) сложно общую сумму по иерархии вывести
|
|||
42
Волшебник
модератор
07.03.17
✎
14:57
|
(39) а потом эта сумма будет учтена трижды :)
|
|||
43
Asmody
07.03.17
✎
14:57
|
(42) Да нет же! Общая сумма одна. Кто сказал, что суммы по тегам надо суммировать?
|
|||
44
Про100Филя
07.03.17
✎
14:59
|
+(36) Ты не понял меня. В таблице родителей прописаны все связи. Получим быстрый "обход" вверх/вниз по дереву.
|
|||
45
Про100Филя
07.03.17
✎
15:01
|
(44) ой это (37).
|
|||
46
Живой Ископаемый
07.03.17
✎
15:04
|
(38) Неистово плюсую
|
|||
47
Живой Ископаемый
07.03.17
✎
15:06
|
Кстати а тег может быть вида
#ГруппаЗатрат.ЭлементЗатрат ? |
|||
48
Вафель
07.03.17
✎
15:06
|
(43) а как в такой структуре собрать общий расход разбитый по статьям/тегам?
|
|||
49
arsik
гуру
07.03.17
✎
15:07
|
(43) Это например так?
За месяц потрачено 100 рублей. ------------------ 50 рублей на еду 50 на бухло 50 на развлешения |
|||
50
Вафель
07.03.17
✎
15:07
|
такая структура удобна для ОТБОРА, но не для ГРУППИРОВКИ
|
|||
51
arsik
гуру
07.03.17
✎
15:08
|
Тэги подойдут там, где нет агрегатных функций.
|
|||
52
Вафель
07.03.17
✎
15:09
|
но ведь никто не делает отчетов:
В каких это числах я тратил деньги на развлечения? |
|||
53
arsik
гуру
07.03.17
✎
15:09
|
(49) О! Родилась мысль.
Чем больше тегов к расходу, тем максимальнее окупились эти расходы. |
|||
54
Волшебник
модератор
07.03.17
✎
15:15
|
(52) Очень здравый вопрос: когда это я ему дал в долг?
|
|||
55
Вафель
07.03.17
✎
15:17
|
(54) долги совсем должны учитываться по другому
|
|||
56
Волшебник
модератор
07.03.17
✎
15:20
|
(55) У меня долги - это те же кошельки с типами "Взято в долг" (кредиторская) и "Выдано в долг" (дебиторская). Пока так. Не хватает ещё поля "Дедлайн", после которого пора вызывать коллекторов или телохранителей.
|
|||
57
Fragster
гуру
07.03.17
✎
15:20
|
про nested sets было?
|
|||
58
Fragster
гуру
07.03.17
✎
15:21
|
я даже на 1с прикручивал в РС, чтобы соединения по иерархии можно было делать
|
|||
59
Волшебник
модератор
07.03.17
✎
15:21
|
(57) было в паре статей выше
|
|||
60
Asmody
07.03.17
✎
16:15
|
(49) Примерно. Например, повел я сына в Мак. Пишем: -630 руб. #еда #дети. А если это всё было в рамках похода в театр, то еще добавляем #развлечения.
Потому что, например, #развлечения — это не только билеты в театр, но и расходы на дорогу, на всякие мелкие игрушки, перекусы и т.д. |
|||
61
Asmody
07.03.17
✎
16:18
|
Вообще, конечно, структура аналитики должна идти от цели — для чего вообще вы ведете учет личных финансов.
|
|||
62
Волшебник
модератор
07.03.17
✎
16:34
|
(61) Да-да. Самое главное, получить план-факт в виде диаграммы с отображением превышений плана.
|
|||
63
Вафель
07.03.17
✎
16:35
|
(62) а как план по тегам составлять?.
Или исходя из предыдуших преиодов? и без учета доходов? |
|||
64
Волшебник
модератор
07.03.17
✎
16:36
|
(63) Не знаю. Теги вы придумали. У меня иерархия статей.
|
|||
65
Вафель
07.03.17
✎
16:37
|
(61) Тогда Asmody ты скажи, какова твоя цель учета?
|
|||
66
Волшебник
модератор
07.03.17
✎
16:43
|
(65) Дожить до зарплаты :)
|
|||
67
Вафель
07.03.17
✎
16:45
|
насколько я знаю есть 2 вида учета: реактивный и проактивный.
1 это: куда делись деньги (расходы по статьям). 2 - На эту штуку 5 руб и ни копейкой больше (бюджет) Может еще какие варианты есть? |
|||
68
Волшебник
модератор
07.03.17
✎
16:47
|
(67) Есть ещё режим "от получки до получки".
~Начало: Пока ЕстьДеньги() Цикл Тратим(); КонецЦикла; ЗапуститьОбработчикОжиданияЗарплаты(); Перейти ~Начало: |
|||
69
Вафель
07.03.17
✎
16:49
|
(68) Отсутвие учета - тоже учет? )))
|
|||
70
Волшебник
модератор
07.03.17
✎
16:53
|
(69) Отсутствие учёта — тоже стиль жизни.
|
|||
71
lock19
07.03.17
✎
17:05
|
(63) По регистрам подобных вопросов нет?
|
|||
72
Torquader
08.03.17
✎
18:03
|
(60) Зачем вообще теги ?
Теги - это связь одной сущности с другой. Просто, если мы пишем статьи затрат, то у нас древовидная структура, и мы не можем одному действию записать несколько статей, нужно будет делить действие на части. А тегов или связей наставить можно сколько угодно: Например:МакДак->Еда,Развлечения, потом Смекта->МакДак,Лечение |
|||
73
Asmody
08.03.17
✎
18:24
|
(65) Понять, во что мне обходится то или иное мероприятие. Задачи "дожить до зарплаты", слава богу, нет.
|
|||
74
Asmody
08.03.17
✎
18:27
|
(72) Ну, в общем-то, да. Это вопрос хороший — включать ли расходы на лечение в "стоимость" предприятия из-за которого пришлось лечиться.
|
|||
75
Torquader
08.03.17
✎
18:30
|
(74) Просто, связи между расходами позволят узнать много нового и интересного.
|
|||
76
Волшебник
модератор
09.03.17
✎
11:29
|
(20) Реализовано. Работает.
|
Форум | Правила | Описание | Объявления | Секции | Поиск | Книга знаний | Вики-миста |