Попал на проект, в котором используется реляционная БД (на постгрес, небольшая). Логически в ней есть связи 1..* и *..*, но не определены внешние ключи (FOREIGN KEYS). Вместе с тем, в DAL используется Entity Framework, и из-за этого его использование выглядит... весьма своеобразным. Навигационных свойств в виде коллекций на сущностях нет, только int/guid ссылки. Чтобы выбрать мастер-сущность вместе с детьми, делается два запроса — на родителя и детей.
Коллекции с "детьми" есть в отдельных классах бизнес-сущностей, которые строятся вручную в репозиториях.
В итоге от ОРМ как такового почти ничего не остаётся. Мотивируется это тем, что якобы запросы с JOIN медленно обрабатываются СУБД. Доказательств с цифрами нет. Может, их делали те, кто проект начинал, но их давно нет (на проекте).
Вопрос: исходя из вашего опыта, насколько это оправдано? Проект не хайлоад, никаких там 10000rps нет.
Здравствуйте, dmitry_npi, Вы писали:
_>Попал на проект, в котором используется реляционная БД (на постгрес, небольшая). Логически в ней есть связи 1..* и *..*, но не определены внешние ключи (FOREIGN KEYS). Вместе с тем, в DAL используется Entity Framework, и из-за этого его использование выглядит... весьма своеобразным. Навигационных свойств в виде коллекций на сущностях нет, только int/guid ссылки. Чтобы выбрать мастер-сущность вместе с детьми, делается два запроса — на родителя и детей.
_>Коллекции с "детьми" есть в отдельных классах бизнес-сущностей, которые строятся вручную в репозиториях. _>В итоге от ОРМ как такового почти ничего не остаётся. Мотивируется это тем, что якобы запросы с JOIN медленно обрабатываются СУБД. Доказательств с цифрами нет. Может, их делали те, кто проект начинал, но их давно нет (на проекте).
_>Вопрос: исходя из вашего опыта, насколько это оправдано? Проект не хайлоад, никаких там 10000rps нет.
Вообще не оправдано, это признак неумения работать с БД.
Более того, даже отсутствие внешних ключей не мешает настроить ссылочные свойства в EF.
Два запроса вместо одного это плохо. Если это еще и в цикле, то совсем ахтунг.
Здравствуйте, dmitry_npi, Вы писали:
_>Попал на проект, в котором используется реляционная БД (на постгрес, небольшая). Логически в ней есть связи 1..* и *..*, но не определены внешние ключи (FOREIGN KEYS). Вместе с тем, в DAL используется Entity Framework, и из-за этого его использование выглядит... весьма своеобразным. Навигационных свойств в виде коллекций на сущностях нет, только int/guid ссылки. Чтобы выбрать мастер-сущность вместе с детьми, делается два запроса — на родителя и детей.
_>Коллекции с "детьми" есть в отдельных классах бизнес-сущностей, которые строятся вручную в репозиториях. _>В итоге от ОРМ как такового почти ничего не остаётся. Мотивируется это тем, что якобы запросы с JOIN медленно обрабатываются СУБД. Доказательств с цифрами нет. Может, их делали те, кто проект начинал, но их давно нет (на проекте).
_>Вопрос: исходя из вашего опыта, насколько это оправдано? Проект не хайлоад, никаких там 10000rps нет.
Может они планировали, что бд может быть любой, в том числе и такой, что не поддерживает внешние ключи.
Здравствуйте, dmitry_npi, Вы писали:
_>Вопрос: исходя из вашего опыта, насколько это оправдано? Проект не хайлоад, никаких там 10000rps нет.
Для хайлоада оправдано (точней не оправдано, а вынужденная мера). Для обычного проекта — нет. Разницы — делать join или один селект — нет. Разницы — делать join или тысячу селектов — есть (но если делать один select вида id in (...), то уже особой разницы не будет). В любом случае join-ы не тормозят.
Могу предположить, что проблема в другом. Есть юз-кейсы, где связанная сущность нужна, а есть — где не нужна. Если стоит join, то он вносит замедление всегда. В Java это решается с помощью lazy/eager fetch. Как в .NET — не знаю, но, полагаю, должно быть что-то похожее. Вероятно они просто не смогли разобраться в ORM.
_>Навигационных свойств в виде коллекций на сущностях нет, только int/guid ссылки. Чтобы выбрать мастер-сущность вместе с детьми, делается два запроса — на родителя и детей.
_>Коллекции с "детьми" есть в отдельных классах бизнес-сущностей, которые строятся вручную в репозиториях. _>В итоге от ОРМ как такового почти ничего не остаётся. Мотивируется это тем, что якобы запросы с JOIN медленно обрабатываются СУБД. Доказательств с цифрами нет. Может, их делали те, кто проект начинал, но их давно нет (на проекте).
_>Вопрос: исходя из вашего опыта, насколько это оправдано? Проект не хайлоад, никаких там 10000rps нет.
Такое иногда бывает не "для чего", а "почему".
Не исключено что когда-то эта база была в Access, а потом её мигрировали в постгрес средствами самого Access. А он при такой миграции, насколько я помню, переносит только таблицы, без связей.
Ну а потом работали над базой не самые опытные люди и не стали делать ключи, а делали всё только в коде.
Бывают, конечно, случаи, когда ускорение работы при отсутствии ключей действительно критично, но это нечасто встречается на практике.
Наличие внешнего ключа действительно замедляет вставку, но обычно это не проблема. Но среди людей бывают странные "перфекционисты", которые любят экономить на спичках.
Я даже лично знал одного, который в дотнете сам делал свой связный список.
Здравствуйте, dmitry_npi, Вы писали:
_>В итоге от ОРМ как такового почти ничего не остаётся. Мотивируется это тем, что якобы запросы с JOIN медленно обрабатываются СУБД. Доказательств с цифрами нет. Может, их делали те, кто проект начинал, но их давно нет (на проекте).
JOIN всё равно придётся делать хотя бы для фильтрации второго запроса. Проблема может быть в другом. Если мастер таблица относительно широкая, а количество подчинённых записей относительно большое, то можно получить набор данных многократно превышающий необходимый, возможно в десятки раз. В целом это довольно дебильная стратегия, если делается по умолчанию без анализа самого запроса и получаемого результата. Особенно учитывая, что хочется именно ОРМ, т.е. получить полноценные объекты или даже их иерархию.
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, dmitry_npi, Вы писали:
_>Мотивируется это тем, что якобы запросы с JOIN медленно обрабатываются СУБД. Доказательств с цифрами нет. Может, их делали те, кто проект начинал, но их давно нет (на проекте).
Вполне возможно, что в начале проекта так оно и было. PostgreSQL только в последнее десятиление стал развиваться очень быстро, а до этого по большей части стагнировал.
Здравствуйте, vsb, Вы писали:
vsb>Могу предположить, что проблема в другом. Есть юз-кейсы, где связанная сущность нужна, а есть — где не нужна. Если стоит join, то он вносит замедление всегда. В Java это решается с помощью lazy/eager fetch. Как в .NET — не знаю, но, полагаю, должно быть что-то похожее. Вероятно они просто не смогли разобраться в ORM.
В Entity Framework это тоже решается, можно указать что инклюдить в данный маппинг, а что оставить за бортом. Просто кажется, что легче иметь один маппинг, который затем постепенно расширется и превращается в God Object. Со всеми вытекающими.
Здравствуйте, vsb, Вы писали: vsb>Могу предположить, что проблема в другом. Есть юз-кейсы, где связанная сущность нужна, а есть — где не нужна. Если стоит join, то он вносит замедление всегда. В Java это решается с помощью lazy/eager fetch. Как в .NET — не знаю, но, полагаю, должно быть что-то похожее. Вероятно они просто не смогли разобраться в ORM.
Приличная СУБД выкидывает join по внешнему ключу, если к результату применяется проекция, отбрасывающая ненужные поля.
Типичный пример:
create view OrdersExt as select *, m.Name as managerName, c.Name as customerName
from orders o
inner join managers m on m.id = o.managerID
inner join customers c on c.id = o.customerID
select o.customerId, o.amount from OrdersExt o
Здесь join можно выбросить при условии, что на orders.managerID и orders.customerID навешены foreign key и они применены. То есть у СУБД есть гарантия того, что join не отбросит никакие записи из orders.
А в .Net всё ещё удобнее — там можно строить запросы динамически, что снижает нужду в подобных view вместе с шансами построить запрос вроде "давайте сначала всё соединим, а потом выбросим лишнее", которые затрудняют работу планировщика запросов.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, dmitry_npi, Вы писали:
_>Попал на проект, в котором используется реляционная БД (на постгрес, небольшая). Логически в ней есть связи 1..* и *..*, но не определены внешние ключи (FOREIGN KEYS). Вместе с тем, в DAL используется Entity Framework, и из-за этого его использование выглядит... весьма своеобразным. Навигационных свойств в виде коллекций на сущностях нет, только int/guid ссылки. Чтобы выбрать мастер-сущность вместе с детьми, делается два запроса — на родителя и детей.
_>Коллекции с "детьми" есть в отдельных классах бизнес-сущностей, которые строятся вручную в репозиториях. _>В итоге от ОРМ как такового почти ничего не остаётся. Мотивируется это тем, что якобы запросы с JOIN медленно обрабатываются СУБД. Доказательств с цифрами нет. Может, их делали те, кто проект начинал, но их давно нет (на проекте).
Ладно джойны, но вручную следить за ссылочной целостностью!? Только потому, что "JOIN медленно обрабатываются"?
Не понятно, что помешало иметь внешние ключи в базе (для соблюдения ссылочной целостности), но формируя запросы к таблицам, там где не нужно, не использовать джойны?
_>Вопрос: исходя из вашего опыта, насколько это оправдано? Проект не хайлоад, никаких там 10000rps нет.
Я как-то работал над проектом, где не использовался FULL JOIN потому что среди поддерживаемых СУБД был мускул (в котором нет такой операции) и Оракл (в котором, якобы, он работал не оптимально, тратя много памяти "в некоторых случаях"). Я тогда подумал, что ребятам виднее и не стал исследовать / переделывать, а зря.
Help will always be given at Hogwarts to those who ask for it.
Здравствуйте, _FRED_, Вы писали:
_FR>Я как-то работал над проектом, где не использовался FULL JOIN потому что среди поддерживаемых СУБД был мускул (в котором нет такой операции) и Оракл (в котором, якобы, он работал не оптимально, тратя много памяти "в некоторых случаях"). Я тогда подумал, что ребятам виднее и не стал исследовать / переделывать, а зря.
FULL JOIN в любой РСУБД относительно тяжелая операция.
Здравствуйте, wildwind, Вы писали:
_FR>>Я как-то работал над проектом, где не использовался FULL JOIN потому что среди поддерживаемых СУБД был мускул (в котором нет такой операции) и Оракл (в котором, якобы, он работал не оптимально, тратя много памяти "в некоторых случаях"). Я тогда подумал, что ребятам виднее и не стал исследовать / переделывать, а зря.
W>FULL JOIN в любой РСУБД относительно тяжелая операция.
Относительно чего? Мне кажется невекроятным, что разработчики Оракла или MSSQL сделали его менее производительным (для общего случая) нежели я (через временную таблицу, потому что эта таблица потом могла использоваться в других запросах).
На "невероятно огромных" массивах данных я не смотрел, но сиквел в моих типовых сценариях справлялся с FULL JOIN отлично: пара (редко от трёх до N) больших таблиц, джойн по одному полю.
Я в то время так и не сумел выгуглить "плохие" сценарии для FULL JOIN (не алгоритмически вроде неудачных данных или отсутствия индексов, а именно особенностей реализации в СУБД), если подскажете, будет интересно.
Help will always be given at Hogwarts to those who ask for it.