Jak przechowywać zamówione przedmioty, które często zmieniają pozycję w DB

Muszę być w stanie przechowywać dużą listę zamówionych przedmiotów w DB. Jak na razie to prosto do przodu:

ID Position OtherFields
 1     45      ...
 2   4736      ...
 3    514      ...
 ...

W zapytaniach zawsze potrzebuję tylko kilku elementów (filtrowanych na podstawie innych pól), ale w odpowiedniej kolejności. Łatwe również umieszczenie indeksu na pozycji i użycie "order by Position".

Teraz problem : przedmioty często zmieniają swoją pozycję, a nie tylko o 1 lub 2. Jeśli ID 2 zmieni pozycję z 4736 na 2000, muszę zaktualizować jego pozycję i Pozycja wszystkich elementów pomiędzy starą pozycją 2000 a 4735, dodając po 1 w każdym wierszu. I to nie tylko jeden identyfikator zmienia się w każdej transakcji, ale kilka, i może być wiele transakcji w krótkim czasie.

Myślę, że najbardziej eleganckim sposobem radzenia sobie z problemem update byłoby użycie linked list zamiast kolumny Position, gdzie mogę po prostu usunąć ID 2 ze starej pozycji, łącząc poprzednika z następcą, a następnie wstawić go gdzie indziej, łącząc go między nowym poprzednik i następca. Byłaby to stała i niewielka liczba aktualizacji na zmianę pozycji i byłby to również mój preferowany sposób obsługi zmian (w moim przypadku w Javie). Jednak to rodzi problem N+1 dla zapytań w prawidłowej kolejności - nawet dla kilku elementów, muszę przejść przez całą listę w najgorszym przypadku, aby dowiedzieć się ich prawidłowej kolejności.

Więc moje pytanie brzmi: co polecacie, aby uzyskać dobrą równowagę między niezbędnymi aktualizacjami i wydajność zapytań?

Jak na razie widzę dwa obiecujące Kierunki:

  1. Czy istnieje DBMS (najlepiej OpenSource), który może obsługiwać połączone listy nie tylko z cukrem składniowym, ale także z dobrą wydajnością, np. używając wewnętrznych indeksów dla połączonych elementów?

  2. Być może byłoby to również opcja, aby po prostu mieć BLOB, w którym cała powiązana lista byłaby przechowywana! Jak duża może mieć Taka Podlinkowana lista / ile pamięci zużyje w DB i po pobraniu powiedzmy 1.000.000 wpisów? Używam Javy + Hibernate w razie potrzeby. Wyobrażam sobie, że przetwarzanie nawet całej listy w pamięci po pobraniu Bloba powinno być dość szybkie!?

Ale oczywiście inne pomysły są mile widziane!

Author: Jörg Brenninkmeyer, 2010-08-03

3 answers

Jeśli złagodzisz ograniczenie, że kolumna Position musi zawierać liczby całkowite od 1 do N i zamiast tego pozwolić, aby zawierała dowolne liczby, możesz efektywnie wyszukiwać i aktualizować.

Możesz wstawić pozycję między dwoma innymi pozycjami a i B, obliczając średnią (A + B) DIV 2. Na przykład, Jeśli A to 10000, A B to 12000, to twoja nowa pozycja to 11000. Od czasu do czasu zabraknie Ci luk z powodu grupowania, w którym to momencie możesz przejrzeć całą tabelę redystrybucja pozycji bardziej równomiernie.

 28
Author: Mark Byers,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-08-03 18:12:10

A co z użyciem dziesiętnego dla pozycji? Jeśli to zrobisz, możesz użyć następującej metody, aby umieścić go między innymi pozycjami:

Oryginalne zapisy to:

ID    Position  Otherfields
--------------------------
1     1.0
2     2.0
.
.
.
5000  5000.0

Następnie przesuń ID 1 do tuż przed 5000

ID    Position  Otherfields
--------------------------
1     4999.9
2     2.0
.
.
.
5000  5000.0

Teraz powiedzmy, że chcesz umieścić ID 2 między 1 A 5000:

ID    Position  Otherfields
--------------------------
1     4999.9
2     4999.91
.
.
.
5000  5000.0

W ten sposób zmieniasz tylko jeden rekord...

Aktualizacja:

Po ponownym przeczytaniu sugestii @ Marka Byersa wydaje się, że nasze rozwiązania są bardzo podobne, choć przy użyciu dziesiętne wydaje mi się dużo prostsze...

 5
Author: Abe Miessler,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-08-03 18:27:51

Poniższe mogą być pomocne. Nie odpowiada bezpośrednio na twoje pytania, ale może rzucić trochę światła na to, jak to zrobić (jeśli jest to możliwe dla Twoich wymagań): {]}

Ranking wpisów w tabeli mysql

 -1
Author: del.ave,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:46:43