NHibernate - настройка производительности с собственным SQL - PullRequest
0 голосов
/ 15 августа 2011

Я пытаюсь использовать NHibernate для отображения графа, построенного со следующими объектами, в реляционную базу данных (код неполный и только для демонстрационной цели, которая должна выглядеть просто). Потенциально классы Node и Edge могут иметь подклассы, и уже есть строка определенных подклассов, унаследованных от класса Node. Для всех отношений наследования в этой модели используется тип отображения: join-subclass (таблица-на-подкласс);

class GraphObject { ... }

class Node : GraphObject {
   List<Edge> IngoingEdges;
   List<Edge> OutgoingEdges;
}

class Edge : GraphObject {
   Node StartNode { get; set; }
   Node EndNode { get; set; }
}

Для соединений между узлами и ребрами используется двойное сопоставление «многие к одному» следующим образом:

многие-к-одному от Edge.StartNode до узлов (.OutgoingEdges); много-к-одному от Edge.EndNode до узлов (.IngoingEdges)

Поскольку в нашем проекте необходимо работать с большими объемными данными (миллионы узлов и ребер), и мы хотели бы сохранить преимущества NHibernate и минимизировать проблемы с производительностью. К сожалению, кажется, что для сохранения или загрузки такой модели требуется почти час. В настоящее время я пытаюсь найти способ завершить загрузку одним оператором и посмотреть, сколько времени это займет. Я сделал несколько попыток и использовал NHibernate Profiler для отслеживания операторов SQL, сгенерированных средой NHibernate, когда выполнял такие вещи, как загрузка всего графа из постоянства данных, но до сих пор мне не удалось устранить это огромное количество отдельных очевидно запрашивает определение начального и конечного узлов для конкретных ребер, которые выглядят как

выберите ... StartNode as .., ..Id as .., ... из ссылки Link, где link.StartNode = 10 (число, указывающее идентификатор узла)

, что означает, что я отчасти страдаю от так называемых проблем N + 1. Так есть ли кто-нибудь, кто сталкивался с подобной проблемой и может дать мне некоторое представление, будь то в нативном SQL или улучшая производительность для этого конкретного случая с помощью других подходов. Я был бы очень признателен за это. Любые вопросы, касающиеся неясных моментов, также приветствуются.

1 Ответ

0 голосов
/ 15 августа 2011

на ум приходят некоторые оптимизации:

это дало бы что-то вроде

// initialize the collections efficiently
session.QueryOver<Node>()
    .Where(n => n.Id == nodeId)
    .Fetch(n => n.IngoingEdges)
    .ToFuture();

firstNode = session.QueryOver<Node>()
    .Where(n => n.Id == nodeId)
    .Fetch(n => n.OutgoingEdges)
    .ToFuture().Value;

var egdeIds = firstNode
    .SelectMany(n => n.IngoingEdges)
    .SelectMany(edge => new [] { edge.StartNode.Id, edge.EndNode.Id });

EagerLoadNode(nodeIds);

void EagerLoadNode(IEnumerable<int> nodeIds)
{
    // initialize the collections efficiently
    session.QueryOver<Node>()
        .Where(n => n.Id.IsIn(nodeIds))
        .Fetch(n => n.IngoingEdges)
        .ToFuture();

    firstNode = session.QueryOver<Node>()
        .Where(n => n.Id.IsIn(nodeIds))
        .Fetch(n => n.OutgoingEdges)
        .ToFuture();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...