Проблема производительности при реализации таблицы закрытия SQLite - PullRequest
0 голосов
/ 25 января 2019

Вначале я говорю, что я довольно плохо знаком с SQL и системами баз данных, поэтому, пожалуйста, извините меня за любые возможные ошибки, которые я могу совершить.

Я использую таблицу закрытия для вставки иерархических данных в базу данных SQLite. Я использую C # (.NET 4.6.1) и предварительно скомпилированную 32-разрядную DLL-библиотеку SQLite (x86) для SQLite версии 3.26.0. Вставленные иерархические данные содержат ~ 240000 элементов, а максимальная глубина дерева не превышает 7.

Моя таблица иерархических элементов:

CREATE TABLE element (elementId INTEGER PRIMARY KEY, parentId INTEGER, elementName TEXT, FOREIGN KEY (parentId) REFERENCES element(elementId));

И моя таблица закрытия определяется как:

CREATE TABLE hierarchy (parentId INTEGER, childId INTEGER, depth INTEGER, FOREIGN KEY(parentId) REFERENCES element(elementId), FOREIGN KEY(childId) REFERENCES element(elementId));

Элементы вставляются с использованием классического стека, который начинается с «корневого» элемента, к которому добавляются члены элемента во время обработки внутри транзакции с использованием:

INSERT INTO element VALUES (<ELEMENT_ID>, <PARENT_ID>'<ELEMENT_NAME');

И я инициализирую таблицу закрытия с отношением «self», используя:

INSERT INTO hierarchy(parentId, childId, depth) VALUES (<ELEMENT_ID>, <ELEMENT_ID>, 0);

Эти вставки не вызывают проблем, их выполнение занимает несколько секунд.

Далее я снова просматриваю все элементы, используя один и тот же метод стека для построения таблицы замыкания (ПРИМЕЧАНИЕ. Вероятно, я мог бы сделать это одновременно с предыдущими инструкциями, однако я делаю это в отдельном цикле, чтобы изолировать проблема производительности) с использованием следующего кода (внутри другой транзакции):

INSERT INTO hierarchy SELECT p.parentId, c.childId, p.depth+c.depth+1 FROM hierarchy p, hierarchy c WHERE p.childId=<PARENT_ID> AND c.parentId=<ELEMENT_ID>;

Однако выполнение этого запроса занимает ЧАСЫ, а может и дни. Время выполнения также становится все длиннее. Я знаю, что он вставляет много элементов в таблицу замыканий (по одной записи на отношение между текущим элементом и всеми его потомками), но я хотел бы знать, можно ли что-нибудь сделать, чтобы улучшить производительность здесь?

Спасибо

1 Ответ

0 голосов
/ 10 марта 2019

Вам нужны индексы для дочерних ключей и родительских ключей. Также оберните все в транзакции.

Еще лучше, используйте один рекурсивный CTE для генерации таблицы замыканий, что-то вроде

with recursive
closure as (
    select elementId, elementId as parentId, 0 as depth from element
    union all
    select closure.elementId, element.parentId, 1 + depth as depth
    from closure, element where closure.parentId = element.elementId
)
select * from closure

Чтобы создать таблицу, используйте что-то вроде create table hierarchy as, чтобы поместить приведенный выше результат в таблицу.

...