|
|
|
Задачка
|
|||
|---|---|---|---|
|
#18+
Sxak ElicЕдинственный способ получить уникальный номер блокировки - это dbms_lock.allocate_unique, который в триггере использовать нельзя. Все остальные способы не гарантируют отсутствие конфликтов.А зачем обязателнь оуникальный? Ну будет происходить ожидание не на той фамилии иногда но редко. Разве ето критично?Дело не в уникальном хэше. Номера блокировок - это очень ценный и ограниченный ресурс, который нельзя использовать как попало. Представь, что некая задача тоже использует пользовательские блокировки в таком же широком диапазоне номеров. И для такой задачи может оказаться крайне критичным напороться на чужую (а не свою) блокировку. Т.е. подсистемы могут пересечься по диапазону используемых номеров блокировок с более катастрофическими последствиями, чем "подумаешь, немножко подождёт". Вячеслав ЛюбомудровАвтономная транзакция?А вот это уже похоже на правду. Выходит, я был не прав. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 12.10.2005, 11:05 |
|
||
|
Задачка
|
|||
|---|---|---|---|
|
#18+
Для решения задачи можно создать дополнительную таблицу со структурой -отдел -фамилия -число_однофамильцев с первичным ключом на (отдел, фамилия) На исходную таблицу повесить триггер for each row before insert or update or delete begin select ... from доп_таблица where :new.отдел=отдел and ... for update; -- for update для многопользовательской работы if inserting and число_однофамильцев=3 then raise_application_error(...) elsif inserting and число_однофамильцев=0 then insert into доп_таблица ... -- если до commit кто-то еще дернется с insert-ом, то получит отлуп из-за уникальности, что не есть хорошо, т.к. в сумме получается только 2 однофамильца. elsif inserting and число_однофамильцев between 1 and 2 then update доп_таблица set число_однофамильцев+1 where ...; elsif deleting and число_однофамильцев>1 then update доп_таблица set число_однофамильцев-1 where ...; elsif -- дальше писать лень, но идея, думаю, понятна end if; end; ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 12.10.2005, 11:18 |
|
||
|
Задачка
|
|||
|---|---|---|---|
|
#18+
ElicДело не в уникальном хэше. Номера блокировок - это очень ценный и ограниченный ресурс, который нельзя использовать как попало. Представь, что некая задача тоже использует пользовательские блокировки в таком же широком диапазоне номеров. И для такой задачи может оказаться крайне критичным напороться на чужую (а не свою) блокировку. Т.е. подсистемы могут пересечься по диапазону используемых номеров блокировок с более катастрофическими последствиями, чем "подумаешь, немножко подождёт". Ага похоже на правду а вот интренесно перекрестные блокировки dbms_lockом оракл отлавливает? Если нет то есть риск получить 2 зависшие сессии ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 12.10.2005, 11:22 |
|
||
|
Задачка
|
|||
|---|---|---|---|
|
#18+
va_kochnevДля решения задачи можно создать дополнительную таблицу со структурой -отдел -фамилия -число_однофамильцев с первичным ключом на (отдел, фамилия) На исходную таблицу повесить триггер for each row .... select ... from доп_таблица where :new.отдел=отдел and ... for update; -- for update для многопользовательской работы ..... insert into доп_таблица ... -- если до commit кто-то еще дернется с insert-ом, Сдается мне что и ето рискует вызвать ...триггер фция может не заметить етого ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 12.10.2005, 11:25 |
|
||
|
Задачка
|
|||
|---|---|---|---|
|
#18+
Sxakа вот интренесно перекрестные блокировки dbms_lockом оракл отлавливает? Если нет то есть риск получить 2 зависшие сессииЭти блокировки ничем не "особенней". dbmslock.sql Код: plaintext 1. 2. 3. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 12.10.2005, 11:50 |
|
||
|
Задачка
|
|||
|---|---|---|---|
|
#18+
Elic Единственный способ получить уникальный номер блокировки - это dbms_lock.allocate_unique, который в триггере использовать нельзя. Все остальные способы не гарантируют отсутствие конфликтов. а нам и не надо уникальный, надо по фалилии ..... Stax ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 12.10.2005, 12:07 |
|
||
|
Задачка
|
|||
|---|---|---|---|
|
#18+
Ну вот что у меня получилось (кому не лень потестите, а то я ухожу) - сразу говорю - весьма нагрузит систему Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58. 59. 60. 61. 62. 63. 64. 65. 66. 67. 68. 69. 70. 71. 72. 73. 74. 75. 76. 77. 78. 79. 80. 81. 82. 83. 84. 85. 86. 87. 88. 89. 90. 91. 92. 93. 94. 95. 96. 97. 98. 99. 100. 101. 102. 103. 104. 105. 106. 107. 108. 109. 110. Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. Код: plaintext и получаем Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 12.10.2005, 12:08 |
|
||
|
Задачка
|
|||
|---|---|---|---|
|
#18+
va_kochnevДля решения задачи можно создать дополнительную таблицу со структурой -отдел -фамилия -число_однофамильцев с первичным ключом на (отдел, фамилия) end; Это пожалуй единственное вменяемое решение задачи. Триггер можно и попроще нарисовать, но главное - дополнительная таблица обеспечит необходимые блокировки. Чтобы обойти проблему одновременной вставки первого сотрудника однофамильца, можно использовать автономную транзакцию. Если после update счётчика SQL%rowcount = 0, нужно в автономной транзакции добавить запись с новой фамилией и счётчиком = 0, а затем снова повторить update. Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. Иногда в БД будут оставаться записи с cnt=0, их время от времени придётся удалять. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 12.10.2005, 12:48 |
|
||
|
Задачка
|
|||
|---|---|---|---|
|
#18+
Вячеслав ЛюбомудровНу вот что у меня получилось (кому не лень потестите, а то я ухожу) - сразу говорю - весьма нагрузит систему .... Если грубо нужен обход мутации лично я пишу несколько иначе в операторном before очищаю pl/sql таблицу імхо бокировку надо выставить до проверки (до фор) иначе успеют вставить мона несколько улучшить сам селект select name, count(*) cnt from t1 where name in (таблица) может ето и неправильно но я сначала организовываю цикл по таблице и селект получается для каждой фамилии .... Stax ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 12.10.2005, 14:01 |
|
||
|
Задачка
|
|||
|---|---|---|---|
|
#18+
Stax.Если грубо нужен обход мутацииТам нет мутации (по крайней мере, я не смог нарваться) Stax. лично я пишу несколько иначе в операторном before очищаю pl/sql таблицуЭто дополнительный триггер - все равно нужет операторный AFTER для проверки результата и строчный BEFORE для блокировок. Хотя, конечно, дело вкуса Stax.імхо бокировку надо выставить до проверки (до фор) иначе успеют вставитьПроверка по фор чисто для ускорения (там ошибка, кстати), чтоб не дергать лишний раз DBMS_LOCK.ALLOCATE_UNIQUE и DBMS_LOCK.REQUEST. Вставить успеют, только если успеют выставить блокировку, тогда уже мы будем ждать Stax. мона несколько улучшить сам селект select name, count(*) cnt from t1 where name in (таблица) может ето и неправильно но я сначала организовываю цикл по таблице и селект получается для каждой фамилии .... StaxЛогично Теперь об ошибках Неправильно ведется таблица блокировок (всегда перезаписывается первая и единственная): Код: plaintext 1. 2. 3. 4. 5. 6. Функция P1.CLEAR_LOCKS нафинг не нужна, т.к. при сбое оператора освободятся все блокировки выставленные в этом операторе (по крайней мере для RELEASE_ON_COMMIT=>TRUE, этакий мини-роллбэк), но нужно почистить таблицу блокировок (P1.SUBMIT_LOCKS), иначе при commit/rollback блокировки освободятся, а мы будем считать что они установлены Как следствие, нет необходимости хранить handle блокировки, соответствующий имени По большому счету таблицу блокировок можно вообще не вести (соответственно, лишние вызовы DBMS_LOCK.ALLOCATE_UNIQUE и DBMS_LOCK.REQUEST) Триггер, естественно, нужно лепить не на любое обновление, а только при обновлении используемых полей (UPDATE OF name) Наверняка, еще куча ошибок/неоптимальностей ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 13.10.2005, 02:06 |
|
||
|
Задачка
|
|||
|---|---|---|---|
|
#18+
вот из этого можно что нибудь придумать http://www.dbazine.com/oracle/or-articles/tropashko8 ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 13.10.2005, 07:12 |
|
||
|
Задачка
|
|||
|---|---|---|---|
|
#18+
Да... мучения похоже будут продолжаться долго... Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58. 59. 60. 61. 62. 63. 64. 65. 66. 67. 68. 69. 70. 71. 72. 73. 74. 75. 76. 77. 78. 79. 80. 81. 82. 83. 84. 85. 86. 87. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 13.10.2005, 07:16 |
|
||
|
Задачка
|
|||
|---|---|---|---|
|
#18+
Да нет, причем тут мучения Просто с MV сушественный недостаток - это "отложенность" проверки до коммита (полчаса вводили, а потом узнали, что так низзя) Хотя может кому и подойдет С блокировками мне больше нравится, т.к. попутно решается и задача найти того, кто держит записи не давая их обновить ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 13.10.2005, 07:21 |
|
||
|
Задачка
|
|||
|---|---|---|---|
|
#18+
Вячеслав ЛюбомудровДа нет, причем тут мучения Просто с MV сушественный недостаток - это "отложенность" проверки до коммита (полчаса вводили, а потом узнали, что так низзя) Хотя может кому и подойдет С блокировками мне больше нравится, т.к. попутно решается и задача найти того, кто держит записи не давая их обновить "Пилите, Шура, пилите..." (с) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 13.10.2005, 07:36 |
|
||
|
Задачка
|
|||
|---|---|---|---|
|
#18+
Вячеслав Любомудров Stax.Если грубо нужен обход мутацииТам нет мутации (по крайней мере, я не смог нарваться) Stax. лично я пишу несколько иначе в операторном before очищаю pl/sql таблицуЭто дополнительный триггер - все равно нужет операторный AFTER для проверки результата и строчный BEFORE для блокировок. Хотя, конечно, дело вкуса я не имел ввиду что в коде есть мутациия, просто берется стандартная схема обхода и даписываем проверку на 3 Очищаю в бифоре в основном из-за рестарта оператора, если не очищать, то таблицу заполним два раза Вячеслав Любомудров Stax.імхо бокировку надо выставить до проверки (до фор) иначе успеют вставитьПроверка по фор чисто для ускорения (там ошибка, кстати), чтоб не дергать лишний раз DBMS_LOCK.ALLOCATE_UNIQUE и DBMS_LOCK.REQUEST. Вставить успеют, только если успеют выставить блокировку, тогда уже мы будем ждать Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. Вячеслав Любомудров Функция P1.CLEAR_LOCKS нафинг не нужна, т.к. при сбое оператора освободятся все блокировки выставленные в этом операторе (по крайней мере для RELEASE_ON_COMMIT=>TRUE, этакий мини-роллбэк), но нужно почистить таблицу блокировок (P1.SUBMIT_LOCKS), иначе при commit/rollback блокировки освободятся, а мы будем считать что они установлены тут я не понял, ну освободятся и добре, что плохого что блокировки снимаеются в случае ошибки Вячеслав Любомудров По большому счету таблицу блокировок можно вообще не вести (соответственно, лишние вызовы DBMS_LOCK.ALLOCATE_UNIQUE и DBMS_LOCK.REQUEST) я бы вел токо таблицу имен, мона даже с distinct ..... Stax ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 13.10.2005, 10:07 |
|
||
|
Задачка
|
|||
|---|---|---|---|
|
#18+
Stax. Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. В принципе, поведение, как у уникального ключа - встретилась дублирующая запись (неподтвержденная) - ждем результата блокирующей транзакции В общем, вот такое (приглаженное) получилось - я думаю добавить еще и отдел будет нетрудно Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58. 59. 60. 61. 62. 63. 64. 65. 66. 67. 68. 69. 70. 71. 72. 73. 74. 75. 76. 77. 78. 79. 80. 81. 82. 83. 84. 85. 86. 87. 88. 89. 90. 91. 92. 93. 94. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 13.10.2005, 10:18 |
|
||
|
Задачка
|
|||
|---|---|---|---|
|
#18+
Вячеслав Любомудров Мы их заблокировали при вставке в триггере BEFORE ... FOR EACH ROWS (точнее повесили блокировки на фамилии). И вторая сессия эти фамилии уже не вставит до нашего окончания транзакции. Понял, вот что такое невнимательность, просто я блокировал непосредственно перед проверкой (перед select count(*) ) А еще забыл сразу написать, блокировать желательно отсортировав по какому то критерию, иначе легко получить деадлок PS зря Вы не очищаете таблицу в операторном before, но это так мысли в слух ...... Stax ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 13.10.2005, 11:01 |
|
||
|
Задачка
|
|||
|---|---|---|---|
|
#18+
Суть идеи: при редактировании оракл блокирует запись, поэтому я попытался свести операции над фамилией+отделом(tab1) к изменению одной записи в другой таблице(tab2). В tab2 фамилия, отдел - первичный ключ, таким образом любые операции над одной фамилией+отдел встанут "в очередь". Проверил работоспобность при insert,delete и update в одной и разных транзакциях, вроде работает. Сразу предупрежу, не работает с множественными изменениями (ограничения на merge). То есть если за один DML удалить, обновить, создать несколько записей в tab1. Ошибки можно измежать, надо просто усовершенствовать триггер tr_tab1_name3_row. Если есть интерес буду рад поделиться дальше... create table tab1( id number primary key, name varchar2(20), otdel number ) / create table tab2( name varchar2(20) not null, otdel number not null, cnt number default 1 not null ) / CREATE GLOBAL TEMPORARY TABLE tab3 ( name VARCHAR2(20) NOT NULL, otdel NUMBER NOT NULL, action char(1) NOT NULL ) ON COMMIT DELETE ROWS / alter table tab2 add constraint pk_tab2 primary key (name,otdel); CREATE OR REPLACE TRIGGER tr_tab2_name3 AFTER UPDATE OF CNT ON TAB2 FOR EACH ROW begin if :new.cnt>3 then raise_application_error(-20000,'Нарушение целостности ...'); end if; end; / create index ind_name3 on tab1 (name asc,otdel asc) / create or replace trigger tr_tab1_name3_row after insert or update or delete of name,otdel on tab1 for each row begin if INSERTING then insert into tab3(name,otdel,action) values (:new.name,:new.otdel,'I'); elsif UPDATING and (:new.name<>:old.name or :new.otdel<>:old.otdel) then insert into tab3(name,otdel,action) values (:new.name,:new.otdel,'I'); insert into tab3(name,otdel,action) values (:old.name,:old.otdel,'D'); else insert into tab3(name,otdel,action) values (:old.name,:old.otdel,'D'); end if; end; / create or replace trigger tr_tab1_name3_st after insert or update or delete of name,otdel on tab1 begin for r in (select * from tab3) loop dbms_output.put_line(R.name||' '||R.otdel||' '||R.action); end loop; merge into tab2 T2 using (select * from tab3) T3 on (T2.name=T3.name and T2.otdel=T3.otdel) when matched then update set T2.cnt=T2.cnt + decode(T3.action,'D',-1,1) when not matched then insert(name,otdel) values(decode(T3.action,'D',null,T3.name),T3.otdel); delete from tab3; end; / ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 13.10.2005, 11:13 |
|
||
|
Задачка
|
|||
|---|---|---|---|
|
#18+
... и еще, в данном примере нет никаких автономных транзакций, ипользования dbms_lock и т.п.. Все операции поиска идут по первичным ключам, должно летать на любых объемах, во всяком случае не тормозить (нет select count(*) from tab group by having - перебор всех записей таблицы - из моего опыта - это подвесит систему при промышленных объемах данных) Спасибо. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 13.10.2005, 11:20 |
|
||
|
Задачка
|
|||
|---|---|---|---|
|
#18+
__LEV__... и еще, в данном примере нет никаких автономных транзакций, ипользования dbms_lock и т.п.. Все операции поиска идут по первичным ключам, должно летать на любых объемах, во всяком случае не тормозить (нет select count(*) from tab group by having - перебор всех записей таблицы - из моего опыта - это подвесит систему при промышленных объемах данных) Спасибо. 1 Если есть индекс(а он у вас есть) то летать будет и вариант с count(*) where name=p_name 2 у вас две дополнительные таблицы а ето нагрузка на систему ввода вывода 3 если заводить другую таблицу то имхо мона обойтись одним триггером for ech row на основной, во второй поставить CHECK (cnt <= 3) (как у Владимира) (непонял зачем так сложно) ..... Stax ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 13.10.2005, 12:06 |
|
||
|
Задачка
|
|||
|---|---|---|---|
|
#18+
Да и где-то в логике напутано Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. Код: plaintext Вроде все правильно, но после коммита в первой сессии получаем во второй Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 13.10.2005, 12:11 |
|
||
|
Задачка
|
|||
|---|---|---|---|
|
#18+
Да согласен, наверно можно упростить. По поводу дополнительных таблиц - блокировки (dbms_lock)тоже ведь хранятся в системных таблицах - теже таблицы,та же нагрузка на ввод/вывод. К тому же количество блокировок ограничено (порядок 10^9), боюсь "на всех не хватит". Могу ошибаться,но мне кажется, что без дополнительной таблицы (своей, системной и т.п.) не обойтись. Сами посудите: анализировать текущую таблицу в любом типе триггера(пакете и т.п.) - бесполезно - не видно не подтвержденных транзакций других сессий. Хочешь упорядочить операции - юзай оракл (ключи, юник индексы и т.п.). Мне кажется что ответив на этот вопрос(с доп таблицами), мы определимся в каком направлении копать. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 13.10.2005, 12:52 |
|
||
|
Задачка
|
|||
|---|---|---|---|
|
#18+
Сначала надо решить Lom-22 , характер задачи, насколько критичны блокировки, как часто происходят операции над таблицей, мож у них например запрещено удаление инфы(отдел кадров) мож это редкие операции, тогда вообще мона блокировать напр dual надавно обсуждали если код позволяет, пользовать простой пример Владимира Вариантов много, но главное нужно блокировть "инсерт" ....... Stax ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 13.10.2005, 13:38 |
|
||
|
Задачка
|
|||
|---|---|---|---|
|
#18+
Lom-22Помогите пожалуйста решить такую задачку: Создать триггер базы данных, не позволяющий вводить в таблицу ААА более трех однофамильцев, работающих в одном отделе. В общем случае решить эту задачу только средствами сервера Oracle нельзя, так как задача является несколько завуалированной классической задачей эмуляции констрейнтов ч/л, кроме самих констрейнтов. А эта задача не имеет решения. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 14.10.2005, 10:46 |
|
||
|
Задачка
|
|||
|---|---|---|---|
|
#18+
TRust Lom-22Помогите пожалуйста решить такую задачку: Создать триггер базы данных, не позволяющий вводить в таблицу ААА более трех однофамильцев, работающих в одном отделе. В общем случае решить эту задачу только средствами сервера Oracle нельзя, так как задача является несколько завуалированной классической задачей эмуляции констрейнтов ч/л, кроме самих констрейнтов. А эта задача не имеет решения. Как это не имеет? на триггерах Вячеслав Любомудров показал с доп таблицей __LEV__ через снапшоты Владимир Бегун Выбирайте ...... Stax ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 14.10.2005, 11:37 |
|
||
|
|

start [/forum/topic.php?fid=52&msg=33321454&tid=1956403]: |
0ms |
get settings: |
9ms |
get forum list: |
19ms |
check forum access: |
4ms |
check topic access: |
4ms |
track hit: |
45ms |
get topic data: |
13ms |
get forum data: |
4ms |
get page messages: |
83ms |
get tp. blocked users: |
2ms |
| others: | 245ms |
| total: | 428ms |

| 0 / 0 |
