|
9 / 6 / 3
Регистрация: 10.01.2020
Сообщений: 330
|
||||||
.NET 4.x Как опитмально поступить в передаче состояния у наследников (foreignkey)03.06.2021, 08:59. Показов 3995. Ответов 55
Всем доброе утро!!!
Представим вот такую задачу. Есть некая онлайн школа допустим программирования. В ней есть несколько курсов по разным ЯП (таблица Course). Есть студенты (таблица Student), которые могут состоять ТОЛЬКО в одном курсе. То есть ТОЛЬКО один язык. В кажом курсе может быть до 1000 студентов. Есть структура базы
У каждого студента есть свой статус/состояние учёбы в этом курсе. Статусов ограниченное количество, поэтому они вынесены в код C# в enum, а в базу передаётся только число этого enum для оптимизации работы БД. Допустим Принят = 0, Сдал = 1, Должник = 2, Не Сдал = 3, Отсутствовал = 4, Так вот задача. В таблицу Course нужно передавать статус от всех студентов. Вот что я имею в виду: Есть курс "Программирование C#". Есть 2 студента в этом курсе. Вася со статусом "Не Сдал" = 3 Петя со статусом "Сдал" = 1 Нужно установить статус курсу, по самому безотвественному студенту, так как курс не может быть закрыт/закончен (со статусом "Сдал" = 1) до тех пор пока хоть один студент находится в другом состоянии. Логика должна быть примерно такая: Если в курсе есть хоть один студент (Student.Status) который в статусе Отсутствовал = 4, то и в Course.Status должно быть Отсутствовал = 4. Если есть хоть один Student.Status Не Сдал = 3, то и в Course.Status должно быть Не Сдал = 3. Если есть хоть один Student.Status Должник = 2, то и в Course.Status должно быть Должник = 2. Если есть хоть один Student.Status Сдал = 1, то и в Course.Status должно быть Сдал = 1. Если есть хоть один Student.Status Принят = 0, то и в Course.Status должно быть Принят = 0. Данные в таблице по студентам обновляются каждый час. То есть каждый час, после обновления таблицы Student нужно проверять статусы наследников, и устанавливать новые статусы в таблицу Course. Данных в таблице (Student) будет более 10млн. И данных в таблице (Course) будет больше 1млн. Как это сделать с минимальной выгрузкой всех данных в программу? Или ещё лучше как сформировать запрос SQL чтобы это всё происходило на стороне СУБД, без получения данных в программу. Или может SQL запрос который получает полуобработанные данные вида: CourseId - Status(уже проверенный) Или может уже существует подход к такой задаче. p.s. Используется MySQL база и библиотека linq2db.
0
|
||||||
| 03.06.2021, 08:59 | |
|
Ответы с готовыми решениями:
55
Фильтрация ForeignKey поля по другому ForeignKey полю в админке Как добавить ключ FOREIGNKEY в таблицу?
|
|
1497 / 1238 / 245
Регистрация: 04.04.2011
Сообщений: 4,363
|
|||
| 03.06.2021, 18:40 | |||
|
1
|
|||
|
Модератор
|
||
| 03.06.2021, 19:04 | ||
|
Как в таком случае сервер будет их обрабатывать без таблицы Статус-Приоритет?
1
|
||
|
1497 / 1238 / 245
Регистрация: 04.04.2011
Сообщений: 4,363
|
|
| 03.06.2021, 19:29 | |
|
Элд Хасп, "Статусов" всего пять. Почему бы сразу не выстроить их по приоритетам ? Тем более, что в интерфейсе вместо статусов будет отображаться из смысловой эквивалент - текст.
Зачем городить огород ради одной грядки, то бишь вытащенного с потолка "приоритета" ?
1
|
|
|
9 / 6 / 3
Регистрация: 10.01.2020
Сообщений: 330
|
|||||||
| 03.06.2021, 22:49 [ТС] | |||||||
|
Данные периодически будут добавляться (Insert) не только (Update). Итого минимум данных в таблице (Student) будет более 10млн. И данных в таблице (Course) будет больше 1млн. Со временем максимум планируется (может за год) (Student) около 30млн. И (Course) около 15млн. Программы-клиенты, которые будут использовать базу, чаще всего будут получать данные именно из таблицы Course. И если каждый раз при получении пересчитывать статус от Student то будет слишком накладно. Вот поэтому думаю, что лучше статус присвоить при самом получении изменений в Student. Таблицу Student программы клиенты будут использовать редко. А Course часто. Статусов не пять, их гораздо больше. Нельзя использовать вычисление по возрастанию. (это только в примере) На текущий момент нужна определённая передача статусов от Student к Course. В дальнейшем добавятся дополнительные, или заказчик скажет, что нужно изменить логику, и присваивать с другими приоритетами. То есть к порядковому числу enum привязываться категорически нельзя. И приоритет там не с потолка. Смотрю в сторону триггеров, но к сожалению ещё с ними не работал (
0
|
|||||||
|
Модератор
|
||
| 03.06.2021, 23:16 | ||
|
При изменении таблицы Студентов хранимые процедуры будут вносить изменения в эту таблицу. Тогда программа-клиент может просто запросить все статусы этого курса и локально обработать их как ей нужно. Будет гораздо проще извлечь любую требуемую информацию. Чем потом под каждый вероятный вид запроса придумывать как его оптимально сделать и, возможно, менять структуру БД.
1
|
||
|
1497 / 1238 / 245
Регистрация: 04.04.2011
Сообщений: 4,363
|
||
| 03.06.2021, 23:35 | ||
|
ХП, вызываемая триггером изменения-добавления "студента", просто извлекает статус из "курса" этого "студента", заодно получая "приоритет". "Приоритеты" "студента" и "курса" сравниваются и, если возникает потребность замены "статуса" в "курсе", выполняется апдейт "курса. Никаких min, три короткие операции : 1) извлечение "приоритета" из "статуса" "студента" (1 запись), 2) извлечение из двух связанных таблиц "курсов" и "справочника приоритетов" действующего "приоритета" и, возможно, 3) апдейт "статуса" в таблице "курсов".
1
|
||
|
14147 / 9375 / 1351
Регистрация: 21.01.2016
Сообщений: 35,319
|
||
| 04.06.2021, 05:52 | ||
|
Я вот из обсуждения не понял на кой тут нужен триггер, который будет срабатывать при каждой вставке строки для вычисления данных, которые понадобятся раз в хрен знает сколько?
Такие вещи нужно вычислять только когда они реально нужны, а не на каждый чих. Если такие запросы более-менее частые, а актульностью данных можно немного поступиться, то можно завести summary table, куда временно складывать результаты вычислений. Но триггер для этого внатуре перебор.
1
|
||
|
Модератор
|
|||
| 04.06.2021, 06:48 | |||
|
Такое обновление (Update + Insert) - это одна операция (транзакция) или нет? И можно ли в БД вызвать автообновление связанных данных не вовремя этой операции, а после неё? Или такое автообновление должно быть вызвано внешним кодом (как изначально и предполагал TC)?
1
|
|||
|
14147 / 9375 / 1351
Регистрация: 21.01.2016
Сообщений: 35,319
|
|||
| 04.06.2021, 07:12 | |||
|
Вообще, я крайне против триггеров. Только когда иначе ну совсем никак, тогда только допускаю их использование.
1
|
|||
|
Модератор
|
||
| 04.06.2021, 07:19 | ||
|
По крайней мере я так понял. Добавлено через 1 минуту Исходя из топика, вопрос TC был такой: Как после обновления БД оптимально составит SQL запрос по обновлению связанных данных, чтобы минимизировать выгрузку данных из БД.
1
|
||
|
14147 / 9375 / 1351
Регистрация: 21.01.2016
Сообщений: 35,319
|
|||
| 04.06.2021, 08:18 | |||
|
1
|
|||
|
Модератор
|
||
| 04.06.2021, 08:24 | ||
|
Ну, так я понял из объяснений. Идёт пакетное обновление очень большого количества записей - то есть может занимать какое-то время хотя бы просто на передачу данных. После этого обновления в БД связанных данных - тоже какое-то время. Тем более что счёт идёт на миллионы засей. И всё это время данные в БД могут быть не в полной мере корректными.
1
|
||
|
14147 / 9375 / 1351
Регистрация: 21.01.2016
Сообщений: 35,319
|
||
| 04.06.2021, 08:29 | ||
|
1
|
||
|
Модератор
|
||
| 04.06.2021, 08:30 | ||
|
Только в них. И как я понял по дальнейшим разъяснениям BeginnerCoderCS, нужный статус (приоритетность?) по сути определяется динамически. Вот насколько динамически - он уже не уточнил. Если однократно при обновлении БД (раз в час), то, наверное, нужна какая-то таблица приоритетов. Если нужна возможность каждому клиенту самому определять какую информацию ему запрашивать, то лучше сделать таблицу Курс-Статус-Количество. Статусов много. Но это "много" от силы 10-20. Поэтому вернуть клиенту по запросу такую небольшую табличку - это совершенно не затратно. А уже в клиенте он пусть как хочет её вертит. BeginnerCoderCS, уточните пожалуйста этот момент.
0
|
||
|
9 / 6 / 3
Регистрация: 10.01.2020
Сообщений: 330
|
||||||||||||
| 04.06.2021, 08:32 [ТС] | ||||||||||||
|
Вот и выходит, что лучше после одновления, сразу пересчитать все статусы. А получение программой-клиентом этих данных (как раз по статусу) получается часто, и каждый раз обрабатывать одни и те же данные (а они могли не меняться несколько дней) будет затратно. Если смотреть пример, то в таблице Course будут много курсов которые уже закончились и стоят со статусом "Сдан". А такие курсы программе-клиенту если и нужны, то крайне редко. А если постоянно дёргать их и пересчитывать, то получится что постоянно придётся брать ВСЮ таблицу Course и постоянно делать одну и ту же операцию по присвоению статуса, независимо от того, были ли изменения у наследников (Student). Если я правильно понял summary table, то статус переданный в Course на основе статусов из таблицы Student это уже и есть в каком-то смысле summary table. Старыми статусами приходится пренебрегать до момента получения новых, но это ограничение апи, и ничего с этим не поделать. 1. Получили обновления из апи в Student 2. Пересчитали все статусы и передали родителю в Course 3. Все программы счастливы получают курсы типа
Но с таким объёмом на регулярной основе я не работал, поэтому и спрашиваю как лучше поступить. Были большие базы, но я оттуда только получал данные, а не добавлял. С триггером проще это сделать, так как в изменяемой или добавляемой записи обязательно есть Student.CounterId, по которому можно получить и все Student.Status и обновить этот статус в Counter.Status, но нагрузка мне кажется будет большой. А вот без триггера (даже с меткой времени) придётся перебирать всё в цикле Вот мысль про метку времени обновления: Если добавить в Student дополнительное поле TimeStamp и вписывать время последнего изменения, то по этому изменению можно будет пересчитывать ТОЛЬКО те строки, в которых были изменения за прошедший час. Типа получить все Student.CounterId в которых Student.TimeStamp > указанной даты. Затем проверять Student.Statusпо указанным Student.CounterId и передавать уже их в Course.Status Но это всё в цикле, а если в цикле, то наверное это придётся делать на уровне приложения, а не в самой СУБД.
0
|
||||||||||||
|
Модератор
|
||||||||||||||||
| 04.06.2021, 08:37 | ||||||||||||||||
|
В моём понимании, нужна БД для таких сущностей
1
|
||||||||||||||||
|
|
||||||
| 04.06.2021, 08:38 | ||||||
|
BeginnerCoderCS, я как-то давно сваял хранимку для MS SQL Server 2008, которая рассчитывает и записывает статусы поставки по позициям спецификации и статусы поставки заявки полностью в зависимости от того, сколько материала присутствует на складе. Работает вроде шустро, по крайней мере тормозов пока не заметил
Вдруг будет полезно, может как-то переделаете для себя ![]()
1
|
||||||
|
Модератор
|
||
| 04.06.2021, 08:45 | ||
|
BeginnerCoderCS, вы неправильно поняли.
Таблица CourseStatus так же будет считаться однократно при обновлении. Но клиент по запросу получит все (не нулевые) Статусы нужного курса. И сам уже решит что ему нужно для анализа. Добавлено через 2 минуты Тогда да, никакого отключения не нужно. Добавлено через 2 минуты BeginnerCoderCS, по поводу полной таблицы статусов курсов. По сути эта информация всё равно будет считаться и вопрос только в том, запомнить её полностью (5-10-20 строк из трёх int полей на каждый курс), или только одну из этих строк.
1
|
||
|
9 / 6 / 3
Регистрация: 10.01.2020
Сообщений: 330
|
|||
| 04.06.2021, 08:46 [ТС] | |||
|
По приоритетам Допустим текущий приоритет: Принят = 0 Отсутствовал = 4 Должник = 2 Не Сдал = 3 Сдал = 1 Затем заказчик скажет, что отключаем передачу статуса Принят = 0, и Должник = 2 в Course, Так как по каким-то причинам, теперь не нужны будут эти статусы. То есть новый приоритет будет Отсутствовал = 4 Не Сдал = 3 Сдал = 1 Или меняем последовательность Не Сдал = 3 Отсутствовал = 4 Должник = 2 Принят = 0 Сдал = 1 Эти изменения могут быть, такак заказчик об этом предупредил. То есть ему не нужно это выводить в интерфейс, это не гибкая настройка, но предупреждение было, что изменения в дальнейшем могут быть, чтобы я не захардкодил этот момент. С доп таблицей приоритетов мне нравится идея, но что-то я не с той стороны захожу наверное, так как не могу реализовать нормально.
0
|
|||
| 04.06.2021, 08:46 | |
|
Помогаю со студенческими работами здесь
40
Как правильно отлавливать Constraint ForeignKey в DAO? Как изменить отображение текста ForeignKey в моделе Как шифровать файлы при передаче на сервер и дешефровать при передаче с сервера на клиент Как сделать каскадный вызов элементов ForeignKey в одной view в Django? Как посмотреть наследников класса Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |
|
Новые блоги и статьи
|
|||
|
Конвертировать закладки radiotray-ng в m3u-плейлист
damix 19.02.2026
Это можно сделать скриптом для PowerShell. Использование
. \СonvertRadiotrayToM3U. ps1 <path_to_bookmarks. json>
Рядом с файлом bookmarks. json появится файл bookmarks. m3u с результатом.
# Check if. . .
|
Семь CDC на одном интерфейсе: 5 U[S]ARTов, 1 CAN и 1 SSI
Eddy_Em 18.02.2026
Постепенно допиливаю свою "многоинтерфейсную плату". Выглядит вот так:
https:/ / www. cyberforum. ru/ blog_attachment. php?attachmentid=11617&stc=1&d=1771445347
Основана на STM32F303RBT6.
На борту пять. . .
|
Символьное дифференцирование
igorrr37 13.02.2026
/ *
Программа принимает математическое выражение в виде строки и выдаёт его производную в виде строки и вычисляет
значение производной при заданном х
Логарифм записывается как: (x-2)log(x^2+2) -. . .
|
Камера Toupcam IUA500KMA
Eddy_Em 12.02.2026
Т. к. у всяких "хикроботов" слишком уж мелкий пиксель, для подсмотра в ESPriF они вообще плохо годятся: уже 14 величину можно рассмотреть еле-еле лишь на экспозициях под 3 секунды (а то и больше),. . .
|
|
И ясному Солнцу
zbw 12.02.2026
И ясному Солнцу,
и светлой Луне.
В мире
покоя нет
и люди
не могут жить в тишине.
А жить им немного лет.
|
«Знание-Сила»
zbw 12.02.2026
«Знание-Сила»
«Время-Деньги»
«Деньги -Пуля»
|
SDL3 для Web (WebAssembly): Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 12.02.2026
Содержание блога
Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами и вызывать обработчики событий столкновения. . . .
|
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 11.02.2026
Содержание блога
Библиотека SDL3 содержит встроенные инструменты для базовой работы с изображениями - без использования библиотеки SDL3_image. Пошагово создадим проект для загрузки изображения. . .
|