Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Базы";
Текущий архив: 2006.11.05;
Скачать: [xml.tar.bz2];

Вниз

Кто понимает смысл ошибки "Таблица мутирует" ?   Найти похожие ветки 

 
ANB ©   (2006-09-04 16:06) [0]

В общем то смысл самой ошибки понятен. И как ее избегать я знаю. А вот смыл ее генерации ? Неужели нельзя ораклу было без нее обойтись ? Почему я не могу селекать в триггере изменяющуюся таблицу ?


 
Desdechado ©   (2006-09-04 16:16) [1]

Потому как, логически рассуждая, не известно, какая часть данных уже изменилась, а какая нет. Ведь, например, UPDATE xxx SET yyy=1 затрагивает все записи, но порядок их обновления командой не задается. Поэтому строить логику на неизвестном поведении сервера некорректно (оно может меняться между версиями).
И, также, неизвестно, какие именно данные ты пытаешься селектить в триггере - старые до обновления, новые после обновления или вперемежку.


 
Val ©   (2006-09-04 16:29) [2]

>ANB ©   (04.09.06 16:06)
Вас очень задевает данный вопрос, до категоричности, как я посмотрю...Но дело в том, что скл сервера реализованы по-разному и стоит, по-моему, принимать их фичи/баги/реализацию как данность...иначе это принимает глупый вид холивара.
offtop: а понимание того, почему нет второго столбца (в прошлой ветке) уже пришло?


 
ANB ©   (2006-09-04 16:35) [3]


> новые после обновления

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


 
ANB ©   (2006-09-04 16:36) [4]


> offtop: а понимание того, почему нет второго столбца (в
> прошлой ветке) уже пришло?

Это в которой ?


 
ANB ©   (2006-09-04 16:51) [5]


> > offtop: а понимание того, почему нет второго столбца (в
>
> > прошлой ветке) уже пришло?
>
> Это в которой ?

Какой столбец ?


 
Desdechado ©   (2006-09-04 16:53) [6]

Ты не забывай, что возможны варианты с автономными транзакциями в триггерах, которые не откатываются при откате главной. Поэтому винегрет будет еще тот при селектах.
Да и
>> новые после обновления
> Меня бы это вполне устроило.
противоречит
> возвращал мне смесь новых и старых строк - это бы меня
> вполне устроило.

Ну, и на закуску.
Это твоя ЧАСТНАЯ задача, для которой удобнее свои подходы. В других задачах - другое видение. На всех не напасешься.


 
Val ©   (2006-09-04 16:58) [7]

В этой.
http://delphimaster.net/view/3-1157033863/&web=1
Столбец N.


 
ANB ©   (2006-09-04 17:10) [8]


> Val ©   (04.09.06 16:58) [7]

И чего в этой ветке непонятного ? Фактически оракл выполняет DDL в отдельной транзакции как один оператор. Что я и хотел выяснить.


> >> новые после обновления

я имел в виду те, которые уже изменились. Ну как то же тот же FB возвращает данные без ошибок (или нет ?) ?


 
Виталий Панасенко   (2006-09-04 19:06) [9]


>
> > Val ©   (04.09.06 16:58) [7]
>
> И чего в этой ветке непонятного ? Фактически оракл выполняет
> DDL в отдельной транзакции как один оператор. Что я и хотел
> выяснить.
>
>
> > >> новые после обновления
>
> я имел в виду те, которые уже изменились. Ну как то же тот
> же FB возвращает данные без ошибок (или нет ?) ?

Подтвержденный другой транзакцией и если читающая транзакция - ReadCommited. Можно сделать "снимок", тогда пофигу все остальные тарнзакции - данные будут только те, которые были на момент старта читающей транзакции.Я о ЖарПтице


 
ANB ©   (2006-09-04 19:17) [10]


> Я о ЖарПтице

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


 
atruhin ©   (2006-09-04 20:36) [11]

> Тогда вопрос - можно ли в FB в триггере уровня строки селекать
> из изменяемой таблицы

Можно. FB чистый версионник, и он спокойно читает данные не учитывая текущие изменения.


 
kaif ©   (2006-09-05 01:17) [12]

А кто-то утверждал, что ORACLE - версионник...
В версионнике как может таблица мутировать?
Вот в IB она никогда не мутирует в режиме ReadCommitted.
Только ногами не бейте...


 
ANB ©   (2006-09-05 09:57) [13]


> А кто-то утверждал, что ORACLE - версионник...

оракл - не версионник. Он иммитация версионника. А вот FB/IB действительно версионники.

Кстати, я понимаю принцип работы транзакций оракла в нормальном режиме. А что происходит в случае сбоя ? Неужто при старте оракл лезет первым делом в RBS и начинает откат слетевших транзакций ?


 
Sergey13 ©   (2006-09-05 10:20) [14]

> [13] ANB ©   (05.09.06 09:57)

Только не в RBS а в Redo. Легко убедиться посмотрев alert файл.


 
ANB ©   (2006-09-05 12:39) [15]


> Только не в RBS а в Redo

Хрен редьки не слаще. Все равно, по идее, не сильно шустро. Таки так и происходит ?


 
Sergey13 ©   (2006-09-05 13:01) [16]

> [15] ANB ©   (05.09.06 12:39)

Может подняться после сбоя можно было бы и быстрее, но зато существует практически 100% гарантия (при грамотном администрировании разумеется) поднимаемости и сохранности данных в БД на "за мгновение до сбоя". Тот же механизм работает при порче носителя и восстановления из бекапа.


 
Petr V. Abramov ©   (2006-09-05 13:07) [17]

>  Неужто при старте оракл лезет первым делом в RBS и начинает откат слетевших транзакций ?
 лезет в redo, накатывает его на rbs, и "естественным образом" откатывает. Если под "случаем сбоя" понимать падение пусть по уважительным причинам. А что в этом такого "неужто"?

> Вот в IB она никогда не мутирует в режиме ReadCommitted.
 точно так же мутирует, только ошибку не выдает.

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


 
ANB ©   (2006-09-05 14:03) [18]


> винигрет будет источником трудноуловимых ошибок.

каких ? Ну давайте представим, что оракл ошибку убрал и вместо этого начал возвращать винегрет. В какой ситуации может что то сломаться ?


 
kaif ©   (2006-09-05 14:19) [19]

2 Petr V. Abramov ©   (05.09.06 13:07) [17]
точно так же мутирует, только ошибку не выдает.
Я не сталкивался с подобным явлением.


 
ANB ©   (2006-09-05 14:20) [20]


> kaif ©   (05.09.06 14:19) [19]

Кстати, а что FB возращает в такой ситуации ?


 
Petr V. Abramov ©   (2006-09-05 14:47) [21]

> Я не сталкивался с подобным явлением.
 ну так FB ошибку не выдает, а выдает муть.

> каких ? Ну давайте представим, что оракл ошибку убрал и вместо этого
> начал возвращать винегрет. В какой ситуации может что то сломаться ?
 да сломаться-то ничего не сломается. но бред будет.
например в триггере на table1 пишем
select count(*) from t1 where field1=1

потом говорим update t1 set fied1 = 1

что должен возвращать select count(*) на каждой стороке?

зайдем по-другому: а покажите пример задачи, которая решается красиво, если ошибка "убрана", инекрасиво, если ошибка "не убрана".


 
evvcom ©   (2006-09-05 14:52) [22]

> [13] ANB ©   (05.09.06 09:57)
> оракл - не версионник. Он иммитация версионника.

Ну вот, опять двадцать пять! Что ты понимаешь под термином "версионник"?

> [12] kaif ©   (05.09.06 01:17)
> В версионнике как может таблица мутировать?

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

> [18] ANB ©   (05.09.06 14:03)

Так тебе ж селект выдал бы СЛУЧАЙНЫЕ данные, разве ж это не винегрет? Если тебе все равно, что выдаст селект, сделай его из dual хотя бы тогда :)


 
ANB ©   (2006-09-05 15:02) [23]


> выдал бы СЛУЧАЙНЫЕ данные

Ни фига они были бы не случайные. Они были бы непредсказуемыми, что не есть одно и тоже. Однако, для проверки, например, зацикливания дерева мне бы любые подошли. Кстати, ошибка при некоторых условиях валится даже если меняется всего одна строка (но не всегда). Например, если вставляется одна строка и производится проверка на дубль ID, то триггер отрабатывает. Если же в эту таблицу делаешь вставку хотя бы 2-х строк одним инсертом, то триггер падает.


 
ANB ©   (2006-09-05 15:03) [24]


> Если же в эту таблицу делаешь вставку хотя бы 2-х строк
> одним инсертом, то триггер падает.

И при этом триггер уровня оператора мне уже не поможет, если мне нужно было в триггере присвоить значение ID.


 
Sergey13 ©   (2006-09-05 15:13) [25]

> [23] ANB ©   (05.09.06 15:02)

Что-то мне помнится Оракл сам отлавливает зацикливания дерева. Плюс непонятно зачем искать дубль ID? Руками что-ли вводишь?


 
ANB ©   (2006-09-05 15:23) [26]


> Что-то мне помнится Оракл сам отлавливает зацикливания дерева.

Только при селекте. А мне надо не допустить этой ситуации при изменении данных. Этим же селектом с генерацией ошибки очень удобно ловить.


> Плюс непонятно зачем искать дубль ID

Значится в первой моей оракловой конторе была сделана иммитация автоинкрементальных полей. В триггере дергался сиквенс. А т.к. исторически сиквенсы были зацикленными, то в триггере же производилась проверка на дубль и если она срабатывала, то сиквенс дергался пока не надоест. Одна запись завсегда нормально вставлялась, 2 - вылетала ошибка мутации. И тут обход через пакет и еще 2 триггера никак не поможет, приходилось вставлять записи по одной в курсоре.


 
evvcom ©   (2006-09-05 15:29) [27]

> [23] ANB ©   (05.09.06 15:02)
> Ни фига они были бы не случайные. Они были бы непредсказуемыми

Согласен.

> Например, если вставляется одна строка и производится проверка
> на дубль ID, то триггер отрабатывает

Заметь, триггер before on each row

> Если же в эту таблицу делаешь вставку хотя бы 2-х строк
> одним инсертом, то триггер падает.

Естественно, на второй записи.
Если тебе пофиг, что вернет селект, то напиши этот селект в отдельной ХП с прагмой автономной транзакции и вызывай ее из своего триггера. Тогда будет все ок.


 
Sergey13 ©   (2006-09-05 15:31) [28]

> [26] ANB ©   (05.09.06 15:23)
> Только при селекте.
Разве? Помнится (хоть и давно это было) я вроде получал ошибку и при апдейте.

> А т.к. исторически сиквенсы были зацикленными

И что? Не хватило размерности?


 
ANB ©   (2006-09-05 15:39) [29]


> в отдельной ХП с прагмой автономной транзакции

А если проблема в уже добавленных/измененных записях ?


> Разве? Помнится (хоть и давно это было) я вроде получал
> ошибку и при апдейте.

Ну откуда ж оракл знает, что ты дерево в таблице нарисовал. Он только при connect by об этом и узнает.


> И что? Не хватило размерности?

За историю фирмы грили, раза три триггера на 0 скидывались.
Неправильно организовали разделение ID между филиалами, а потом уже "исторически сложилось".


 
evvcom ©   (2006-09-05 15:45) [30]

> [29] ANB ©   (05.09.06 15:39)
> А если проблема в уже добавленных/измененных записях ?

И что? Я так понимаю, тебе надо узнать используется такой id или нет? ХП проверит, видит ли она такой id и вернет результат триггеру. Триггер дальше решает, что с этим делать. Хочешь raise сделай, хочешь сиквенс еще дерни и опять в ХП.


 
Sergey13 ©   (2006-09-05 15:48) [31]

> Ну откуда ж оракл знает, что ты дерево в таблице нарисовал.
> Он только при connect by об этом и узнает.

Наверное ты прав, а мне пригрезилось. Попробовал - получил как ты говоришь.


 
Petr V. Abramov ©   (2006-09-05 15:49) [32]

> Однако, для проверки, например, зацикливания дерева мне бы любые подошли
  че-то Вы перемудрили, возможно. Как насчет четкого описания, что Вы хотите сделать и почему именно в триггере?


 
ANB ©   (2006-09-05 15:56) [33]


> Petr V. Abramov ©   (05.09.06 15:49) [32]

ОК.
1)
Имеем парентовое дерево. ID, ID_Parent.
При добавлении/изменении данных пользователь может умудриться дерево зациклить. Чтобы не дать ему этого сделать, нужно выполнить проверку по своей же таблице. В триггере уровня строки этого сделать нельзя. Этот случай можно разрулить либо триггером уровня оператора (сохранив массив строк) либо вообще изменять данные только через хранимку (там такой проблемы не вылезет).
2) Имеем триггер, который присваивает ID первичному ключу. Т.к. сиквенс зациклен, то в триггере производится обращение к своей таблице для проверки дублирования. При вставке более одной строки за раз триггер падает. Обойти вообще никак, только если вставлять всегда по одной строке.
3) И на закузку. Ошибка мутации может вылезти и без триггеров.


 
evvcom ©   (2006-09-05 15:57) [34]

> [29] ANB ©   (05.09.06 15:39)
> Неправильно организовали разделение ID между филиалами,
> а потом уже "исторически сложилось".

Если они писали в одну базу, то ID нафиг не надо было разделять.
Если базы разные, а потом репликация в главную, мое имхо, лучше сделать составной ПК из id филиала и сиквенса.


 
evvcom ©   (2006-09-05 16:01) [35]

> [33] ANB ©   (05.09.06 15:56)
> В триггере уровня строки этого сделать нельзя.
> Обойти вообще никак, только если вставлять всегда по одной
> строке.

Том Кайт думает по-другому. См. [27] последнее предложение и [30].

> 3) И на закузку. Ошибка мутации может вылезти и без триггеров.

Поподробнее можно?


 
kaif ©   (2006-09-05 16:04) [36]

Petr V. Abramov ©   (05.09.06 14:47) [21]
ну так FB ошибку не выдает, а выдает муть.


Приведи пример кода, который выдаст такую муть.
Я готов попробовать.
Зачем зря спорить?

Может я неправ, а прав - ты.

Только учти, что в FB существует большое разнообразие типов транзакций: и wait и nowait и Snapshot и ReadCommitted и RepeatebleRead. И всевозможные лок-конфликты, которые FB успешно отлавливает.

Не знаю, как в ORACLE.

По крайней мере, работая из JAVA, я не смог от ORACLE получить ничего
кроме READ COMMITTED в том смысле, который, как известно периодически "мутирует". Возможно плохо старался.
:)


 
Petr V. Abramov ©   (2006-09-05 16:12) [37]

> 3) И на закузку. Ошибка мутации может вылезти и без триггеров.
 это как Вам удалось??! Научи! :)

> либо вообще изменять данные только через хранимку (там такой проблемы не вылезет).
 вот самое лучшее решение.

> то в триггере производится обращение к своей таблице для проверки дублирования.
 а не эффективнее ли вставки тоже делать хранимкой и действия предпринимать по факту ошибки

P.S. не люблю триггеры, запутывают они систему, а во-вторых, если в случае крайней необходимости надо руками данные подправить, может нехорошо получиться


 
ANB ©   (2006-09-05 16:13) [38]

Пример (правда бессмысленный) получения ошибки мутации на функции :

create table table2 (ID integer, Parent_ID integer, Status integer)

insert into table2 (ID, Parent_ID, Status)
select rownum, rownum - 1, decode(mod(rownum,2),0,4,5) from dual
connect by level <= 10000

commit;

CREATE OR REPLACE FUNCTION t2_prev_status (p_prev_id INTEGER)
  RETURN INTEGER
AS
  v_status   INTEGER;
BEGIN
  SELECT NVL (MIN (status), 0)
    INTO v_status
    FROM table2
   WHERE ID = p_prev_id;

  RETURN v_status;
END;

select t2.*, t2_prev_status(t2.PARENT_ID) from table2 T2

update table2 T2
set Status = t2_prev_status(t2.PARENT_ID)
where ID = 1

я нарывался на эту ошибку и в реальном проекте. Ох и матов было . . .


> работая из JAVA

Ограничения JDBC/Net. Оракл позволяет управлять уровнем изоляции, но этим мало кто пользуется.


 
evvcom ©   (2006-09-05 16:17) [39]

> [36] kaif ©   (05.09.06 16:04)

Пример кода:
Создаешь TestTable с полями (Id, Value) и такую же LogTable. Вставляешь в TestTable 2 записи (1,1) и (2,1). Далее триггер on TestTable after update on each row:
 insert into LogTable
 select * from TestTable;
Далее выполняешь
update TestTable
 set
   value = value + 1;
и смотришь LogTable. По идее должен получить 4 записи:
(1,2), (2,1), (1,2), (2,2)
или
(1,1), (2,2), (1,2), (2,2)
в зависимости от того, какую запись первой обновит update. Вот из-за этой зависимости результата от очередности изменения записей Oracle и выдает ошибку про "мутации" :)


 
ANB ©   (2006-09-05 16:18) [40]


> См. [27] последнее предложение и [30].

Согласен. Но к каждому триггеру придется тогда добавить еще и хранимку.

> Если базы разные, а потом репликация в главную, мое имхо,
>  лучше сделать составной ПК из id филиала и сиквенса.

1) Базы, есно, разные.
2) Составной PK не сильно кузяво (в связке из 30-40 таблиц да с извратами это сильно неудобно будет)
3) Исторически сложилось, млин. Достаточно было запихать номер филилала в млдашие ращряды ID, а не в старшие (ограничив собственно ID 20000000) и сиквенса бы хватило весьма надолго. Но - см. начало фразы.



Страницы: 1 2 вся ветка

Форум: "Базы";
Текущий архив: 2006.11.05;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.57 MB
Время: 0.042 c
15-1160386826
Сало
2006-10-09 13:40
2006.11.05
Крамник-Топалов


2-1161242975
fisherman
2006-10-19 11:29
2006.11.05
Добавление записи в таблицу Oracle


15-1160751654
oldman
2006-10-13 19:00
2006.11.05
Возвращаясь к теме ХР...


3-1157093965
Delphi basic
2006-09-01 10:59
2006.11.05
Неправильный расчет выражений в SQL


3-1157636937
Ольга
2006-09-07 17:48
2006.11.05
Триггер, который пишет в таблицу на другом сервере





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский