Модераторы: LSD
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Безопасное изменение ID у записи 
V
    Опции темы
WolfAlone
Дата 6.7.2011, 04:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


В экстазе
***


Профиль
Группа: Завсегдатай
Сообщений: 1010
Регистрация: 16.9.2008
Где: Рай

Репутация: нет
Всего: 5



Доброго времени суток!

Стоит задача: перенести какую-то запись "в конец" таблицы. Для этого, на мой взгляд рациональнее всего, просто сменить ID этой записи на последний + 1. Выглядеть всё это будет примерно так:
Код

SELECT @max_id := (MAX(id)+1) FROM table;
UPDATE table SET id=@max_id WHERE id = 2;


Но тут сразу же возникает два вопроса:
1. Не случится ли однажды такое, что в один прекрасный момент, сможет затесаться другой конкурентный INSERT-запрос, между SELECT и UPDATE который добавит в таблицу какую-то запись, после чего @max_id уже перестанет значение последнего существующего ID в реальном времени?
2. После того, как я меняю ID какой-то записи на последний + 1, значение счётчика "AUTO INCREMENT" у таблицы не увеличивается! В виду чего, при следующем INSERT'e возникает ошибка о том, что запись с таким номером уже существует! (*при вставке записи, её ID я не указываю, т.к. именно для этого существует автоинкрементное поле [ID])

Первое, что приходит в голову - это изменить ID у всех записей в таблице. Но по моему, это как то не правильно... Если записей будет миллион и нужно будет переместить первую запись в конец таблицы, то предётся изменить ID у миллиона записей!? Возможно, есть какое-то более "красивое" решение?

Второе, что пришло в голову - это взять все данные (собрать в массив), удалить ту запись, которую нужно переместить в конец, а затем вставить её снова. Таким образом, обе проблемы отпадают, но... по моему это тоже как-то не совсем правильно! Зачем удалять данные и снова вставлять их же, если они уже есть в таблице?


--------------------
И сказал Бог: "Тогда я построю свой мир с блэк-джеком и шлюхами!"

Ф топку Ubuntu, Debian наше фсё!

(с) Евгений Вольф
PM MAIL WWW ICQ Skype   Вверх
WolfAlone
Дата 6.7.2011, 05:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


В экстазе
***


Профиль
Группа: Завсегдатай
Сообщений: 1010
Регистрация: 16.9.2008
Где: Рай

Репутация: нет
Всего: 5



*в качестве примера, можно считать, что в роли Сервера БД - выступает MySQL 5.1/5.5


--------------------
И сказал Бог: "Тогда я построю свой мир с блэк-джеком и шлюхами!"

Ф топку Ubuntu, Debian наше фсё!

(с) Евгений Вольф
PM MAIL WWW ICQ Skype   Вверх
Zloxa
Дата 6.7.2011, 09:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Чо?
****


Профиль
Группа: Завсегдатай
Сообщений: 3473
Регистрация: 12.9.2008

Репутация: 11
Всего: 161



Цитата(WolfAlone @  6.7.2011,  04:35 Найти цитируемый пост)
. Не случится ли однажды такое, что в один прекрасный момент, сможет затесаться другой конкурентный INSERT-запрос,

Случится.
Против конкурентного инсерта нет простого приема. MySQL, афайк не поддерживает аналог ораклиных сиквенсов и ФБшных генераторов. Можно похожий механизм реализовать самостоятельно, но тогда, по факту конкурентных инсертов происходить не будет,они будут строго упорядочены.

Если два запроса объединить в один и использовать режим изоляции read commited, то конкурентные апдейты сериализуются и не приведут к рассогласованию данных
Код

UPDATE table SET id=(SELECT coalesce((MAX(id)+1),1) FROM table) WHERE id = 2;

В этом же случае конкурентый инсерт производить средствами insert into table select coalesce(max(id)+1,1), :fld1, :fld2,:fld3 from table. Так же в режиме изоляции read commited. Но производительность такой вставки будет оставлять желать лучшего и инсерты будут таки не конкурентны а последовательны.

нууу о том что дизайн говен, думаю говорить не стоит, вы и сами это видите. 






--------------------
Достоверно известно, что 89% людей доверяют статистике взятой с потолка smile
PM   Вверх
Akina
Дата 6.7.2011, 12:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Советчик
****


Профиль
Группа: Модератор
Сообщений: 20581
Регистрация: 8.4.2004
Где: Зеленоград

Репутация: 13
Всего: 454



Цитата(WolfAlone @  6.7.2011,  05:35 Найти цитируемый пост)
Для этого, на мой взгляд рациональнее всего, просто сменить ID этой записи на последний + 1. 

А на мой взгляд, разумнее дополнительное поле, задающее порядок.


--------------------
 О(б)суждение моих действий - в соответствующей теме, пожалуйста. Или в РМ. И высшая инстанция - Администрация форума.

PM MAIL WWW ICQ Jabber   Вверх
WolfAlone
Дата 6.7.2011, 15:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


В экстазе
***


Профиль
Группа: Завсегдатай
Сообщений: 1010
Регистрация: 16.9.2008
Где: Рай

Репутация: нет
Всего: 5



Zloxa, скажите пожалуйста, если "проблему" попробовать решить вот таким вот образом:

Код

SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
START TRANSACTION;
UPDATE table SET id=(SELECT coalesce((MAX(id)+1),1) FROM table) WHERE id = 2;
COMMIT;


Это даст гарантию того, что никакой конкурентный запрос не "вклинится" и не нарушит целостность данных?


--------------------
И сказал Бог: "Тогда я построю свой мир с блэк-джеком и шлюхами!"

Ф топку Ubuntu, Debian наше фсё!

(с) Евгений Вольф
PM MAIL WWW ICQ Skype   Вверх
Zloxa
Дата 6.7.2011, 15:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Чо?
****


Профиль
Группа: Завсегдатай
Сообщений: 3473
Регистрация: 12.9.2008

Репутация: 11
Всего: 161



Точно не уверен, я не являюсь экспертом по mysql. 
Мне кажется этот запрос таки заблокирует простой инсерт, но я не могу за то поручиться.
Практика - критерий истины. ))) Попробойте в одной сессии начать транзакцию, выполнить аптдейт и не коммититься.
Во второй сессии, просто выполните простой инсерт. Желателльно в диртириде. Если он встанет на блокировке - радуйтесь ))

Цитата(Akina @  6.7.2011,  12:33 Найти цитируемый пост)
А на мой взгляд, разумнее дополнительное поле, задающее порядок. 

Тут согласен. ПК для этих целей использовть не гоже. Лучше для этих целей использовать суррогатное поле. Однако же проблема конкурентной модификации ранга все равно останется.


--------------------
Достоверно известно, что 89% людей доверяют статистике взятой с потолка smile
PM   Вверх
WolfAlone
Дата 6.7.2011, 18:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


В экстазе
***


Профиль
Группа: Завсегдатай
Сообщений: 1010
Регистрация: 16.9.2008
Где: Рай

Репутация: нет
Всего: 5



Что-то у меня никак не получается создать 2 одновременных конкурентных запроса, описанных выше. Подскажите пожалуйста ПО для реализации такого эксперемента! *Желательно под винду.


--------------------
И сказал Бог: "Тогда я построю свой мир с блэк-джеком и шлюхами!"

Ф топку Ubuntu, Debian наше фсё!

(с) Евгений Вольф
PM MAIL WWW ICQ Skype   Вверх
LSD
Дата 6.7.2011, 19:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Leprechaun Software Developer
****


Профиль
Группа: Модератор
Сообщений: 15718
Регистрация: 24.3.2004
Где: Dublin

Репутация: 24
Всего: 538



Цитата(WolfAlone @  6.7.2011,  19:49 Найти цитируемый пост)
Что-то у меня никак не получается создать 2 одновременных конкурентных запроса, описанных выше. Подскажите пожалуйста ПО для реализации такого эксперемента! *Желательно под винду. 

Любой SQL клиент у которого можно:
- открыть 2 сессии к базе
- отключить автокомммит


--------------------
Disclaimer: this post contains explicit depictions of personal opinion. So, if it sounds sarcastic, don't take it seriously. If it sounds dangerous, do not try this at home or at all. And if it offends you, just don't read it.
PM MAIL WWW   Вверх
WolfAlone
Дата 6.7.2011, 19:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


В экстазе
***


Профиль
Группа: Завсегдатай
Сообщений: 1010
Регистрация: 16.9.2008
Где: Рай

Репутация: нет
Всего: 5



LSD, пробовал SQL Maestro for MySQL и HeidiSQL (то, с чем работаю повседневно). Две сессии открываю в виде двух экзепмляров программы, отключить "автокоммит" и запустить тразакцию пытаюсь вот так:

Код

SET AUTOCOMMIT = 0;
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
START TRANSACTION;


Результат что-то пока нулевой...

В ответ получаю:
Код

/* 0 rows affected, 0 rows found. Duration for 3 queries: 0,093 sec. */


Никакой блокировки не происходит. Подозреваю, что что-то я делаю не так.

В настройках софта поставил "Keep connection alive", что бы не от отключался/подключался после каждого запроса.


--------------------
И сказал Бог: "Тогда я построю свой мир с блэк-джеком и шлюхами!"

Ф топку Ubuntu, Debian наше фсё!

(с) Евгений Вольф
PM MAIL WWW ICQ Skype   Вверх
WolfAlone
Дата 7.7.2011, 01:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


В экстазе
***


Профиль
Группа: Завсегдатай
Сообщений: 1010
Регистрация: 16.9.2008
Где: Рай

Репутация: нет
Всего: 5



Помогите пожалуйста с экспериментом, что-то у меня не получается совсем!


--------------------
И сказал Бог: "Тогда я построю свой мир с блэк-джеком и шлюхами!"

Ф топку Ubuntu, Debian наше фсё!

(с) Евгений Вольф
PM MAIL WWW ICQ Skype   Вверх
Zloxa
Дата 7.7.2011, 09:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Чо?
****


Профиль
Группа: Завсегдатай
Сообщений: 3473
Регистрация: 12.9.2008

Репутация: 11
Всего: 161



совершенно не понятно чему там можно не получаться.
У меня нет ни одной инсталляции MySQL, но у меня есть подключение к MS SQL. MS SQL, как и МySQL является блокировочником и, очень вероятно, что они будут работать одинаково.

Запускаю интерпарйз манаджер, соединяюсь с базой. Открыаю новое окно. Выполняю.
Код

use northwind
insert into Region values (777,'JustTestIt');

northwind - демонстрационная база данных, которая разворачивается автоматически, при установке sql сервера.
Я создал запись, над которой буду производить эксперименты.
Далее, в том же окне
Код

set transaction isolation level serializable
begin transaction
update region set RegionId = (select max(RegionID)+1 from region) where RegionId = 777

Открываю новое окно, это конкурируюая сессиия. Выполняю
Код

use northwind
set transaction isolation level read uncommitted
begin transaction
insert into region values (7777,'Hello')

С удовольствием наблюдаю, что insert завис - встал на блокировке. Значит моя гепотеза была верна.
Иду в первое окно
выполняю
Код

rollback

Радостно наблюдаю, что тот инсерт отвис и выполнился
повторно выполняю в этом же окне
Код

set transaction isolation level serializable
begin transaction
update region set RegionId = (select max(RegionID)+1 from region) where RegionId = 777

Радостно наблюдаю что теперь этот запрос завис(встал на блокировке).
Перехожу во второе окно, деаю там rollback, это запрос в первом окне завершается, делаю роллбэк и там

Резюме - можно пользовать, достаточность serializable доказана.

Теперь повторяю этот же эксперимент, но вместо serializable использую read committed. Первый же кейс не приводит к зависанию инсерта. Он происходит успешно, а значит может привести к потере согласованности данных. На момент фиксации транзакции, новоприсвоенный айди в базе уже будет не наибольшим.

Резюме - необходимость serializable доказана.

Однако все равно не понятно к чему весь этот пляс, если что делать с счетчиком автоинкремента - все равно не понятно.

Это сообщение отредактировал(а) Zloxa - 7.7.2011, 09:51


--------------------
Достоверно известно, что 89% людей доверяют статистике взятой с потолка smile
PM   Вверх
Akella
Дата 7.7.2011, 12:58 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Творец
****


Профиль
Группа: Модератор
Сообщений: 18485
Регистрация: 14.5.2003
Где: Корусант

Репутация: 3
Всего: 329



Не играйся с ID  smile , может лучше будет просто сделать вставку, а старую запись удалить?
 
Код
Insert into table1 select from table1 where id = 2

PM MAIL   Вверх
WolfAlone
Дата 7.7.2011, 14:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


В экстазе
***


Профиль
Группа: Завсегдатай
Сообщений: 1010
Регистрация: 16.9.2008
Где: Рай

Репутация: нет
Всего: 5



Akella, во истину мудрое решение! Спасибо!

P.S. Вопрос закрыт.


--------------------
И сказал Бог: "Тогда я построю свой мир с блэк-джеком и шлюхами!"

Ф топку Ubuntu, Debian наше фсё!

(с) Евгений Вольф
PM MAIL WWW ICQ Skype   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Общие вопросы по базам данных"
LSD
Zloxa

Данный форум предназначен для обсуждения вопросов о базах данных не попадающих под тематику других форумов:

  • вопросам по СУБД для которых нет отдельных подфорумов
  • вопросам которые затрагивают несколько разных СУБД (например проблема выбора)
  • инструменты для работы с СУБД
  • вопросы проектирования БД
  • теоретически вопросы о СУБД

Данный форум не предназначен для:

  • вопросов о поиске разлиных БД (если не понимаете чем БД отличается от СУБД то: а) вам не сюда; б) Google в помощь)
  • обсуждения проблем с доступом к СУБД из различных ЯП (для этого есть соответсвующие форумы по каждому ЯП)
  • обсуждения проблем с написание SQL запросов, для этого есть форум Составление SQL-запросов
  • просьб о написании курсовой, реферата и т.п., для этого есть Центр помощи или фриланс биржа
  • объявлений о найме специалистов, для этого есть раздел Объявления о найме специалистов

Если вы не соблюдаете эти правила, не удивляйтесь потом не найдя свою тему/сообщение. ;)


Полезные советы:

При написании сообщения постарайтесь дать теме максимально понятное название. В теме максимально подробно опишите проблему. Если применимо укажите: название базы данных и версии (MySQL 4.1, MS SQL Server 2000 и т.п.); используемых язык программирования; способа доступа (ADO, BDE и т.д.); сообщения об ошибках.

Для вставки кода используйте теги [code=sql] [/code].

Литературу по базам данных можно поискать здесь.

Действия модераторов можно обсудить здесь.


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, LSD, Zloxa.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | СУБД, общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0640 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.