Mysql поставить запись между двумя записями порядок - PullRequest
0 голосов
/ 09 июля 2020

вот записи, и мы хотим переместить id # 1 между # 3 и # 4

id  title   sort
1     a      1
2     b      2
3     c      3
4     d      4
5     e      5
6     f      6

метод первый:

получить номер сортировки # 3 и плюс 1 и обновите сортировку # 1 с этим, чтобы у нас было

id  title   sort
1     a      4
2     b      2
3     c      3
4     d      4
5     e      5
6     f      6

, а затем плюс сортировка с 1 по 4 и все записи после этого

, и у нас есть

id  title   sort
1     a      4
2     b      2
3     c      3
4     d      5
5     e      6
6     f      7

и после сортировки

id  title   sort
2     b      2
3     c      3
1     a      4
4     d      5
6     e      6
6     f      7

он работает нормально, но представьте, что у нас есть 2000000 записей, и все записи должны быть обновлены ...

метод второй

получить сумму вида # 3 и # 4 и разделить на 2 => (3 + 4) /2=3.5 и просто поместить его для сортировки # 1

id  title   sort
2     b      2
3     c      3
1     a      3.5
4     d      4
5     e      5
6     f      6

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

есть ли какой-нибудь трюк или метод mysql / mariadb для этого?

1 Ответ

0 голосов
/ 09 июля 2020

Ваш метод «перетащить на полпути между элементами» может быть лучшим.

Давайте go с BIGINT UNSIGNED, так как он дает вам 64 бита в 8 байтах. Менее хорошо: DOUBLE даст вам 53 бита в 8 байтах, и еще немного забавного дела с показателями. DECIMAL дает вам больше битов за счет большего количества байтов, но при этом не устраняет необходимость в следующем коде.

  • Вы знаете, какую строку поставить «после» на основе пользовательского ввода?
  • Найдите строку после, используя ORDER BY ... ASC LIMIT 1.
  • Усредните два значения; проверьте, равно ли среднее любому из них - если да, то у вас плохой случай.

Отступление ... 2M строк. Начните с 2K, 4K, 6K и т.д. c в качестве значений sort (2M * 2K = 4G, предел BIGINT UNSIGNED.)

Это говорит о том, что вы можете сжать 2K элементов между любой смежной парой . Однако в худшем случае повторной вставки точно после первого значения вы получите только 11 вставок, прежде чем ударится о стену. 11 ~ = log2 (2000). То есть повторная сортировка может быть быстрой, но до 1 раза из 11 это будет дорого.

(Пожалуйста, не спорите между 2K, что означает 2000 и 2048; это не имеет значения для алгоритм.)

Итак, что делать, если нет места для вставки нового значения сортировки? Перестройка чисел заблокировала бы таблицу (из 2M строк) на «слишком длинную», поэтому давайте постараемся этого избежать.

Как насчет этого:

Возьмите 10 строк до и после (2 SELECT с ORDER BY и LIMIT). Исправьте эти sort значения, чтобы они были распределены равномерно.

  • Возможно, нет проблем с попаданием в начало или конец таблицы; было бы меньше 20 рядов. И есть молчаливые границы 0 и 4G-1.
  • Если 20 рядов мало, то расширяйте промежуток.
  • Делайте все это (включая исходный, простой, наполовину code) в транзакции.
  • Используйте FOR UPDATE для всех (?) SELECTs, чтобы другие потоки были заблокированы.
  • Проверить на взаимоблокировки. Если вы столкнулись, начните полностью. (Вторая попытка, вероятно, обнаружит, что попытка на полпути работает нормально - потому что какой-то другой поток завершил распространение значений сортировки.)

Время:

  • на полпути, даже с транзакцией, вероятно, потребуется миллисекунда или около того.
  • Более сложный случай не займет много времени, несмотря на блокировку и обновление 20 строк.
  • Вы вероятно, может обрабатывать 1К действий в секунду.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...