Форум программистов, компьютерный форум, киберфорум
Наши страницы
Oracle
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.60/5: Рейтинг темы: голосов - 5, средняя оценка - 4.60
Qazan
214 / 62 / 25
Регистрация: 30.04.2013
Сообщений: 854
Записей в блоге: 10
1

Duplication entry

18.09.2018, 21:11. Просмотров 860. Ответов 18

Добрый день!

Имею следующее(в процедуре)
SQL
1
2
3
4
5
6
7
8
9
CREATE PROCEDURE insertIfNotExist(KEY IN VARCHAR, col1 IN VARCHAR, col2 IN VARCHAR)
IS
BEGIN
 INSERT INTO ENTRY(id, KEY, col1, col2)                                          ---       1
      SELECT S_ENTRY.nextval, KEY, col1, col2 FROM DUAL                  ---      1
      WHERE NOT EXISTS (SELECT 1 FROM ENTRY e WHERE e.key = KEY);    ---       1
 
 commit;                                                                                 ----      2
END;

Верно ли я понимаю:
а) Все, что под 1 происходит в одной транзакций.
б) между 2 и 1 в другом потоке может произойти все, что угодно.

Таким образом, возможна ситуация когда перед commit значения уже будут в БД (процедура исполнилась в другом потоке) и возникнет duplication entry exception?

Добавлено через 1 минуту
PS: И exception возникнет лишь в случае, если уровень изоляции - serializable ?
0
Лучшие ответы (1)
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
18.09.2018, 21:11
Ответы с готовыми решениями:

Adding Entry Will Cause Text List To Exced 64k.entry Not Added
Вот такая ошибка выскакивает, понятно что идет переполнение rtitem Body, туда добавляеться куча...

Ошибка с циклом Map.Entry entry:hashMap.entrySet
Пытаюсь спарсить сайт со списком и подробнее о каждом элементе. Всё делал по уроку на youtube. При...

Desktop Duplication API - Получение серии скриншотов с экрана
Представляю свой исходник: // via https://pastebin.com/JCYPtd5j #include "stdafx.h" #include...

Map.Entry
Господа. Может кто-нибудь более менее доступно разъяснить про Map.Entry Джавадок пять раз...

Entry Point
Каким образом можно сделать entry point не в функции main(), а в какой-либо другой? Меня это...

18
mibin
73 / 67 / 16
Регистрация: 21.10.2009
Сообщений: 378
19.09.2018, 09:18 2
Если вызвать эту процедуру то она в теории может быть распаралелена ораклом, но это всё равно можно считать одним потоком. А вот входящие параметры использоваться не будут, т. к. их названия совпадают с названиями полей.
0
Grossmeister
Модератор
3404 / 2457 / 419
Регистрация: 21.01.2011
Сообщений: 10,779
19.09.2018, 10:18 3
Цитата Сообщение от Qazan Посмотреть сообщение
Все, что под 1 происходит в одной транзакций.
Транзакция в Oracle начинается с первым оператором DML сессии или с оператором после последнего COMMIT/ROLLBACK.
Транзакция в Oracle заканчивается после выдачи очередного COMMIT/ROLLBACK.
1
AGK
759 / 660 / 195
Регистрация: 24.11.2015
Сообщений: 2,157
20.09.2018, 12:02 4
Цитата Сообщение от Qazan Посмотреть сообщение
возможна ситуация когда перед commit значения уже будут в БД
Если значения уже занесены в другой сессии и там завершилась транзакция, то процедура вернет ошибку, и транзакция в этой сессии откатится
0
mibin
73 / 67 / 16
Регистрация: 21.10.2009
Сообщений: 378
20.09.2018, 12:12 5
Не факт что будет ошибка, тут зависит от наличия ограничений, о которых мы ничего сейчас не знаем.
1
Qazan
214 / 62 / 25
Регистрация: 30.04.2013
Сообщений: 854
Записей в блоге: 10
20.09.2018, 16:31  [ТС] 6
mibin, Уровень изоляции - сериализуемый.

Насколько понял, это из-за того что чтение не блокирующее ввиду уровня изоляции.
0
mibin
73 / 67 / 16
Регистрация: 21.10.2009
Сообщений: 378
20.09.2018, 16:47 7
Уровень изоляции serializeble говорит о том, что пока ты не завершишь свою транзацию (commit/rollback) ты не сможешь читать изменения других, но когда ты вставляешь или изменяешь данные оракл сверяет их с реальными данными в таблицах, т.е. он смотрит если есть значения закомиченные другой транзакцией. Он всегда сверяет реальные значения независимо от уровня изоляции.

В чем именно возникла проблема?
0
Qazan
214 / 62 / 25
Регистрация: 30.04.2013
Сообщений: 854
Записей в блоге: 10
20.09.2018, 17:01  [ТС] 8
mibin,
Верно ли я понимаю statement поста:

Сперва выполняется чтение т.е. -
SQL
1
SELECT 1 FROM ENTRY e WHERE e.key = KEY
Далее INSERT если сработало условие
SQL
1
NOT EXISTS
Т.е. Вы говорите, что чтение
SQL
1
SELECT 1 FROM ENTRY e WHERE e.key = KEY
, не будет работать во время транзакций?


PS: Проблема в том, что при параллельном исполнений процедуры поста возникает duplicate entry exception (ORA-0001)
0
mibin
73 / 67 / 16
Регистрация: 21.10.2009
Сообщений: 378
20.09.2018, 17:24 9
Если про порядок действия, то да, сначала чтение(включает в себя все условия отсечения), потом вставка данных.
Если есть ограничение уникальности то вы должны их получить только если другая транзакция уже вставила и закомитела до вас.

По поводу запроса:
SQL
1
SELECT 1 FROM ENTRY e WHERE e.key = KEY
Это будет работать по следующей логике:
В таблице поле key должно ровняться само себе, он не будет смотреть что у Вас есть переменная с таким же именем, он забьет на это и будет сравнивать поле само с собой. Чтобы этого не было необходимо задавать имена переменным отличные от имена полей в таблицах.
1
Qazan
214 / 62 / 25
Регистрация: 30.04.2013
Сообщений: 854
Записей в блоге: 10
20.09.2018, 17:42  [ТС] 10
mibin, по факту имя отличное.
Это просто для примера так написал, чтобы не раскрывать бизнес-схемы.

Добавлено через 4 минуты
UPD: На тестовых стендах такой ошибки не наблюдалось, но при выводе на эксплуатацию прома иногда выдает exception упомянутый выше.


Полагаю проблема именно в high-concurrency.

Добавлено через 2 минуты
mibin, хочу понять механизм возникновения
0
mibin
73 / 67 / 16
Регистрация: 21.10.2009
Сообщений: 378
20.09.2018, 17:43 11
Полагаю проблема именно в high-concurrency.
Судя по всему так и есть, кто-то вставляет данные (и комитит) раньше другого, как это решить сказать не могу, т.к. тут нужен весь код для анализа и еще бизнес смысл понимать скорее всего нужно изменить логику ограничений.
0
Qazan
214 / 62 / 25
Регистрация: 30.04.2013
Сообщений: 854
Записей в блоге: 10
20.09.2018, 17:51  [ТС] 12
mibin,
Цитата Сообщение от mibin Посмотреть сообщение
, как это решить сказать не могу,
Пока сделал так: отлавливаю ошибку
SQL
1
exception WHEN DUP_VAL_ON_INDEX
Цитата Сообщение от mibin Посмотреть сообщение
кто-то вставляет данные (и комитит) раньше другого,
Т.е. все-таки это происходит между
SQL
1
SELECT
и
SQL
1
INSERT
.
Таким образом чтение не лочит таблицу.


constraint только 1: уникальный индекс по
SQL
1
KEY
Добавлено через 1 минуту
Цитата Сообщение от mibin Посмотреть сообщение
нужно изменить логику ограничений.
Изменить не могу, необходимо хранить уникальные записи по соответствующему ключу.
Одинаковые значения(c точки зрения ключа) необходимо игнорить.
0
mibin
73 / 67 / 16
Регистрация: 21.10.2009
Сообщений: 378
20.09.2018, 18:21 13
Лучший ответ Сообщение было отмечено Qazan как решение

Решение

Некорректно разделять транзакцию на части..тем более один SQL оператор...insert + select это один SQL оператор...считайте что просто кто-то раньше вас успел закомититься и всё.
1
Qazan
214 / 62 / 25
Регистрация: 30.04.2013
Сообщений: 854
Записей в блоге: 10
20.09.2018, 19:28  [ТС] 14
mibin, То, чтоmibin, кто-то успел закоммититься раньше чем я, означает, что мне доступны эти данные, а значит условие
SQL
1
NOT EXISTS (SELECT 1 FROM ENTRY e WHERE e.key = KEY)
ложно.
Т.е. INSERT исполнятся не будет.

По такому сценарию exception не возможен.

Но, дело в том, что он есть.

Соответственно, чтение не лочит таблицы и происходит параллельно.
О, транзакции я согласен. Она не делима по определению.

Дело, видимо, в том, что суть транзакция не означает, что что-то происходит в критической секций.

В принципе логично, зачем лочить при чтений, если откатывать нечего, соответственно суть понятия транзакция не ломается.

Добавлено через 8 минут
Возможно, также, что чтение произошло непосредственно перед коммитом в другой сессий. Поскольку читатели не блокируются писателями.

Спасибо!
Наконец то понял.

Теперь вот думаю, резонна ли вообще эта проверка
SQL
1
NOT EXISTS (SELECT 1 FROM ENTRY e WHERE e.key = KEY)
если можно вообще просто отлавливать exception всегда.


Т.е. что быстрее эта проверка(немного вероятностная) или отлов exception-на
0
mibin
73 / 67 / 16
Регистрация: 21.10.2009
Сообщений: 378
20.09.2018, 21:10 15
Тут важно понимать чем serializeble отличается от read commited. В уровне изодяции serializeble пока вы не выполните commit или rollback вы ничьих изменений используя selectне увидите, только операторы изменегия данных их увидят, а в режиме read commited вы будете видеть изменения на момент запуска SQL оператора, но операторы изменения данных всё равно будут видеть все изменения во время вставки, т. е.в режиме serializeble если перед вызовом процедуры вы не ввзываете commit или rollback то изменения вы не увидите, а в режиме read commited увидете, но только те которые сделаны были до запуска вашего insert select.

Добавлено через 1 час 30 минут
Вообще странная сииуация когда к вам из всех щелей в базу лезут одинаковые данные, если сделаете exception то один дубль не даст вставиться другим нормальным данным, тут либо смотреть в сторону log errors для insert либо серьёзно задуматься о том всё ли правильно спроектировано.

Добавлено через 6 минут
Вот тут пример работы log errors http://www.interface.ru/home.asp?artId=23190
вот тут подробнее https://oracle-base.com/articles/10g/dml-error-logging-10gr2
0
Qazan
214 / 62 / 25
Регистрация: 30.04.2013
Сообщений: 854
Записей в блоге: 10
20.09.2018, 22:34  [ТС] 16
Цитата Сообщение от mibin Посмотреть сообщение
всех щелей в базу лезут одинаковые данные
Согласен, хочу предложить сыпать в таблицу все подряд.
А далее, тем кому необходимы уникальные данные использовать view.


Цитата Сообщение от mibin Посмотреть сообщение
exception то один дубль не даст вставиться другим нормальным данным
А можно по подробней здесь

Данные утеряются? Разве в другой сессий не будет ожидания транзакций?
0
mibin
73 / 67 / 16
Регистрация: 21.10.2009
Сообщений: 378
20.09.2018, 22:42 17
SQL
1
2
3
 INSERT INTO ENTRY(id, KEY, col1, col2)
      SELECT S_ENTRY.nextval, KEY, col1, col2 FROM DUAL
      WHERE NOT EXISTS (SELECT 1 FROM ENTRY e WHERE e.key = KEY);
Если в реальной жизни тоже dual тогда проблем нет, если таблица и тогда вставляется несколько данных, то будет проблема, что из 10 записей дублем окажется только 1 не вставятся все 10.

Согласен, хочу предложить сыпать в таблицу все подряд.
А далее, тем кому необходимы уникальные данные использовать view.
Это реально плохое решение для производительности, в качестве варианта можно сериализовать доступ в процедуре вставке данных (dbms_lock) или блокировать таблицу целиком а после отпускать. Использование view да еще с distinct будет существенно тормозить при большом наборе данных.
Но тут надо понимать на сколько важна скорость вставки...в это варианте всё будет медленнее существенно.
1
Qazan
214 / 62 / 25
Регистрация: 30.04.2013
Сообщений: 854
Записей в блоге: 10
20.09.2018, 22:48  [ТС] 18
Цитата Сообщение от mibin Посмотреть сообщение
Если в реальной жизни тоже dual
Да, в реальной жизни также DUAL только данные из аргументов процедуры.

Цитата Сообщение от mibin Посмотреть сообщение
Использование view да еще с distinct будет существенно тормозить при большом наборе данных.
Понял, Спасибо.

Цитата Сообщение от mibin Посмотреть сообщение
(dbms_lock) или блокировать таблицу целиком а после отпускать
Это будет лучше чем отлавливать exception?
0
mibin
73 / 67 / 16
Регистрация: 21.10.2009
Сообщений: 378
21.09.2018, 07:32 19
Это будет лучше чем отлавливать exception?
Вот у вас есть сиквенс, наверняка там первичный ключ висит, теперь предположим что какой-то нехороший человек пересоздал сиквенс с уменьшением номера и теперь каждая его работа будет вызывать ошибку уникальности до тех пор пока его номер не превысит максимальный в таблице. Вот в этот момент физически могут нарушаться сразу 2а правила на уникальность-один по первичному ключу, второй по полям и игнорить отловом ошибки будете оба.
По моему мнению ошибки лучше проверять, чем натыкаться на ошибки, но иногда это единственное решение, надо смотреть на картину целиком и взвесить все плюсы и минусы.
0
21.09.2018, 07:32
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
21.09.2018, 07:32

Entry Not Found In Index
На свой страх и риск решил построить отчет на вьюхе. Бегаю по NotesEntry, вытаскиваю че надо, но...

Entry Not Found In Index
собственно сабж использую для создания навигатора createviewNavFromCategory...

Entry Is No Longer In View
Всем добрый день! Прошу помочь разобраться с ошибкой. Скрипт пробегается по документам и по...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
19
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2018, vBulletin Solutions, Inc.
Рейтинг@Mail.ru