Я использую Django и PostgreSQL, но я не совсем привязан к Django ORM, если есть лучший способ сделать это с необработанными операциями SQL или базой данных.
У меня есть модель, которая требует последовательного заказа. Операции поиска обычно извлекают весь список по порядку. Самая распространенная операция с этими данными - переместить строку в конец списка, с подмножеством промежуточных элементов, всплывающих вверх, чтобы заменить предыдущий элемент следующим образом:
(operation on A, with subset B, C, E)
A -> B
B -> C
C -> E
D -> D
E -> A
Notice how D does not move.
Как правило, подмножество элементов будет содержать не более 50 элементов, но базовый список может увеличиться до десятков тысяч записей.
Наиболее очевидный способ реализовать это с помощью простого целочисленного поля порядка. Это кажется неоптимальным. Это требует компромисса, заключающегося в том, чтобы сделать столбец упорядочения позиций неуникальным, тогда как неуникальность требуется только на время операции модификации. Чтобы увидеть это, представьте минимальную операцию с использованием A с подмножеством B:
oldpos = B.pos
B.pos = A.pos
A.pos = oldpos
Даже если вы сохранили позицию, во второй строке вы нарушили ограничение уникальности. Кроме того, этот метод делает атомарность проблематичной - ваша операция чтения должна выполняться до записи, в течение которой ваши записи могут измениться. Документация по обработке транзакций по умолчанию в Django не решает эту проблему, хотя я знаю, что это должно быть возможно в SQL с использованием уровня блокировки транзакций «REPEATABLE READ».
Я ищу альтернативные структуры данных, которые более соответствуют этому шаблону использования. Я посмотрел на этот вопрос для идей.
В одном предложении предлагается решение в стиле десятичной дроби Дьюи, в котором операции вставки выполняются численно между существующими значениями, поэтому вставка A между B и C приводит к:
A=1 -> B=2
B=2 -> A=2.5
C=3 -> C=3
Это решает проблему уникальности столбца, но создает проблему, состоящую в том, что столбец должен быть числом с плавающей запятой указанного числа десятичных знаков. Либо я переоцениваю и сохраняю гораздо больше данных, чем мне нужно, или система становится ограниченной любой произвольной десятичной длиной, которую я навязываю. Более того, я не ожидаю, что использование будет даже над базой данных - некоторые ключи будут перемещаться гораздо чаще, чем другие, что делает это решение быстрее. Я мог бы решить эту проблему путем периодической нумерации базы данных, но, похоже, хорошей структуре данных следует избегать этого.
Другая структура, которую я рассмотрел, это связанный список (и варианты). Это имеет преимущество, заключающееся в упрощении модификации, но я не уверен в ее свойствах в отношении SQL - упорядочивание такого списка в запросе SQL кажется болезненным, а извлечение непоследовательного подмножества списка - ужасно поисковые свойства.
Помимо этого, есть B-деревья, различные двоичные деревья и так далее. Что вы рекомендуете для этой структуры данных? Существует ли стандартная структура данных для этого решения в SQL? У первоначальной идеи перехода с последовательными целыми числами действительно будут проблемы с масштабированием, или я вижу проблемы там, где их нет?