Стратегия таблицы на подкласс при заполнении большого дерева из базы данных с использованием NHibernate
Я использую NHibernate для загрузки большого дерева объектов разных типов. Отображение реализовано с использованием стратегии "таблица на подкласс". Я определил базовый класс "Node", который имеет только несколько полей (NodeId, ParentId, NodeType) и несколько подклассов, которые наследуются от Node, и добавляют свои собственные поля.
Реализация этого подхода была проста, и я не могу пожаловаться на производительность. Большое дерево из 10 000 объектов разных типов заполняется на моей старой машине в течение нескольких сотен миллисекунд с использованием одной и той же передачи. Однако есть одна вещь, которая меня беспокоит: такая стратегия приводит к генерации сложного запроса, в котором таблица Node внешне объединяется с любой другой таблицей, соответствующей определенным подклассам. Хотя это нормально, когда число различных подклассов невелико, в случае увеличения их числа сложность OUTER JOIN также возрастет.
Определение таблицы для каждого класса, кажется, не изящный вариант, и он будет работать медленно при выборе данных из базового класса (из-за UNION). Другие варианты увеличивают количество обращений к серверу базы данных.
Так что, по вашему мнению, является наилучшей практикой при заполнении большого дерева, состоящего из объектов разных типов? Есть ли что-нибудь лучше таблицы на подкласс?
2 ответа
Для предотвращения объединений вы можете использовать стратегию "таблица на класс". Тогда каждый подкласс находится в одной и той же таблице и различается по столбцу дискриминатора.
Я использовал этот подход для 15 подклассов.
Единственным недостатком является то, что вы не можете определить ненулевые ограничения для свойств подклассов, и вы должны обрабатывать это в коде.
Вы имеете дело с двумя проблемами здесь:
Обход большой иерархии.
Большой граф объектов.
Обе области, где у ORM будут проблемы. ORM станет здесь узким местом, поэтому вам, возможно, придется отступить от стандартной функциональности ORM и перейти к хранимым процедурам, чтобы справиться с тяжелым подъемом, когда вы сталкиваетесь с узкими местами.
Используя хранимые процедуры, вы можете использовать план выполнения SQL для решения проблем, выявления медленных точек запросов и определения возможностей индексирования.
Из документации Nhibernate (это кеш, который Nhibernate не работал)
Используйте ручной код ADO.NET в узких местах.
В критически важных для системы областях системы некоторые виды операций (например, массовое обновление / удаление) могут выиграть от прямого ADO.NET. Но, пожалуйста, подождите, пока вы не узнаете, что что-то является узким местом. И не думайте, что прямой ADO.NET обязательно быстрее. Если вам нужно использовать прямой ADO.NET, возможно, стоит открыть NHibernate ISession и использовать это соединение SQL. Таким образом, вы все равно можете использовать ту же стратегию транзакций и базовый поставщик соединений.