2013-10-27 5 views
0

Контекст:
У меня есть база данных SQLite со столом, глядя, как это:
CREATE TABLE items (item TEXT, position INTEGER)SQLite: как сгруппировать запросы UPDATE и задержать изменения после?

Эта таблица содержит несколько миллионов записей. Столбец position индексируется.

Мой интерфейс иногда создает кучу обновлений для применения на столбце position. Строки, которые необходимо обновить, не идентифицируются по их идентификатору, потому что обновления могут быть в широком диапазоне элементов, а список всех идентификаторов может быть очень дорогим. К примеру, куча может быть действие, как обновление "добавить в положение +10> = 500 & положение < = 10000" - "добавить в положение -3> = 100000 & положение < = 100003" и т.д.

Проблема: Условные позиции обновлений обновления обновления: все на основе значений позиций перед сгруппированным обновлением. Если я последовательно выполняю каждое действие обновления сгруппированного обновления, тогда, возможно, (и на самом деле есть) проблема «перекрытия» после одного обновления.

К примеру:

item | position 
it1 | 1 
it2 | 2 
it3 | 3 
it4 | 4 
it5 | 5 
it6 | 6 
it7 | 7 

Если у меня есть эта куча обновлений: "добавить + 2 в положение> = 5 & положение < = 6" - «добавить - 2 в положение> = 3 & положение < = 4" и преобразовать его в этом SQLite запросов:
UPDATE items SET position=position-2 WHERE position >= 5 AND position <= 6
UPDATE items SET position=position+2 WHERE position >= 3 AND position <= 4

Я буду иметь этот результат:

it1 | 1 
it2 | 2 
it3 | 5 
it4 | 6 
it5 | 5 
it6 | 6 
it7 | 7 

Вместо того, что я хочу, это сказать:

it1 | 1   { it1 | 1 } 
it2 | 2   { it2 | 2 } 
it3 | 5   { it5 | 3 } 
it4 | 6 ===> { it6 | 4 } 
it5 | 3   { it3 | 5 } 
it6 | 4   { it4 | 6 } 
it7 | 7   { it7 | 7 } 

Это из-за «перекрывание» от одной операции к другой.

Моя первая идея состояла в том, чтобы использовать СЛУЧАЙ так:

UPDATE items SET position=CASE WHEN position >= 5 AND position <= 6 THEN position-2 WHEN position >= 3 AND position <= 4 THEN position+2 ELSE position END
Это решение прекрасно работают, но это очень и очень медленно, так как это, кажется, что SQLite выполнить это на миллионы записей моей таблицы, даже если Обновленная информация не затрагивает основную сторону.

Так я изменил это так:
UPDATE items SET position=CASE WHEN position >= 5 AND position <= 6 THEN position-2 WHEN position >= 3 AND position <= 4 THEN position+2 ELSE position END WHERE (position >= 5 AND position <= 6) OR (position >= 3 AND position <= 4)
Это решение отлично работает, и это очень быстро, так как SQLite выполнить обновление только на соответствующих строках.

Вопрос: Как я могу иметь 10, или даже, возможно, 100 обновления действия, чтобы сделать в одной связке обновления, запрос может стать очень большим, и это не выглядит очень ... «красивый "/"хороший".

Как вы думаете, есть ли более красивый способ справиться с этим? Может ли SQLite выполнить некоторые запросы «UPDATE», выбирая затронутую строку в первый раз, а затем эффективно обновлять строку после?

Идеи? Думал ?

спасибо!

ответ

0

Добро пожаловать в SO.

У меня есть ощущение, что есть альтернативное решение, но persuant на ваш вопрос, я хотел бы изменить схему:

CREATE TABLE items (item TEXT, position INTEGER, position_tmp INTEGER) 

Запустите обновления, как это:

UPDATE items SET position_tmp = position + 1 WHERE 100 <= position AND position < 200 
UPDATE items SET position_tmp = position - 3 WHERE 500 <= position AND position < 1000 
... 

Наконец,

UPDATE items SET position = position_tmp 

Может показаться неприятным, чтобы надолго иметь дополнительные position_tmp (и это так), но SQLite не поддерживает переименование или удаление столбцов, и даже если бы это было так, это было бы более эффективным, чтобы сохранить его.

EDIT:

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

В зависимости от того, что вам нужно, может быть возможно использовать номера с плавающей запятой для их заказа. Например, 0,1, 2,5, 5,0. Если вы хотите вставить что-то в качестве второго элемента, вставьте его в положение 1.3. Если вы хотите удалить последний элемент, просто удалите его.

В противном случае вы в основном имеете дело с вековой проблемой наличия списка с быстрой вставкой и удалением.

+0

Благодарим вас за ответ. Эффективно это может быть решением. У меня была аналогичная идея: добавьте столбец «флаг». Перед каждым массовым обновлением установите для всех флагов строк значение 0 и запрос на обновление, обновите строку только с помощью флага «0» и установите флаг «1» в одно и то же время. Моя самая большая проблема: эта колонка занимает много места (значения хранятся в миллионы раз), и требуется время для обновления.И я чувствую, что создать дополнительную колонку для ответа на логическую проблему - это не очень хорошо. Что вы думаете об альтернативном решении? Возможно, я ошибаюсь с самого начала проблемы. –

+0

В SQLite нет решения, которое я бы назвал исполнителем в пределах параметров, которые вы описали. –

+0

Есть ли какая-либо документация/блог/лучшие практики о том, как управлять позиционированием строк в базе данных? –

0

Вы должны увидеть вашу проблему алгоритмический:

Добавление A к элементам из положения P1 в P2:

positions in [P1, P2] will become [P1+A, P2+A] 
positions in [P2+1, P2+A] will become [P1, P1+A-1] (shift: -(P2-P1+1)=P1-P2-1) 

SQL:

UPDATE items SET position=CASE position <= P2 THEN position+A ELSE position-P1-P2-1 WHERE position BETWEEN P1 AND P2+A; 

Для вычитания S для элементов из позиции Q1 в Q2:

positions in [Q1, Q2] will become [Q1-S, Q2-S] 
positions in [Q1-S, Q1-1] will become [Q2-S+1, P2] (shift: P2-P1+1) 

SQL:

UPDATE items SET position=CASE position >= Q1 THEN position-S ELSE position+P2-P1+1 WHERE position BETWEEN Q1-S AND Q2; 

Таким образом, с помощью одного из этих двух запросов, вы будете иметь возможность обновлять все соответствующие позиции в одном операторе. Просто используйте соответствующие (P1, P2, A) или (Q1, Q2, S).

+0

Хм да. Интересно. Моя проблема заключается в том, что по-прежнему существует проблема с сгруппированным обновлением: начальные позиции каждого «атомного» обновления в связке связаны с начальными позициями строки (до сгруппированного обновления). Но я думаю, что легче было бы зафиксировать позиции каждого «атомного» обновления группы, чтобы быть относительно предыдущего обновления в связке, и использовать ваше решение. Эта штука похожа на «дельта-обновление», предназначенное для слияния некоторых движущихся операций, чтобы предотвратить слишком много обновлений с внешнего интерфейса. –