Страница 1 из 1

Убийство запросом (insert into select from)

Добавлено: 23 авг 2006, 06:20
Lars
В книге Т. Кайта по Oracle дается пример многоверс. архитектуры СУБД и приводится след. пример:

Код: Выделить всё

for х in (select * from t)
loop
insert into t values (x.username, x.user_id, x.created);
end loop ;

Синтаксис ORACLE, идея след.: открываем запрос на выборку и проходя по набору добавляем в эту же табличку данные!

Вот такая ХП получилась у меня в FB 1.5.3:

Код: Выделить всё

CREATE PROCEDURE TEST_PROC 
as
declare variable name_product varchar(80);
begin
  i=0;
  for select name from product into :name_product
  do
  begin
    insert into product (NAME) VALUES (:name_product );--уник. индекса по NAME нет
  end
  suspend;
end;
И получил максимум использ. проц. времени на fbserver.

Это так должно быть???

Добавлено: 23 авг 2006, 07:53
Lars
Проверил на FB 1.5.3 и FB 2 RC 4.

На фб 2 работает около уже около 15 минут, нагрузка на проц. полная, файл с 7 Мб увелич. до 152 Мб.

Добавлено: 23 авг 2006, 08:21
Dimitry Sibiryakov
Это такой старый баян, что его уже никто и не принимает всерьез. Да, жар-птичку INSERT INTO table SELECT FROM table загоняет в бесконечный цикл. Малой кровью не фиксится ибо заложено в самой глубине архитектуры.

Добавлено: 23 авг 2006, 10:08
kdv
потому что insert into select from все зависит от селекта. если селект выбирает записи поштучно (а не буферизирует все например при plan sort, или group by), то и insert идет поштучно. отсюда зацикл.
и никакого сравнения многоверсионной архитектуры СУБД тут нет.

Добавлено: 23 авг 2006, 21:32
Lars
kdv писал(а): и никакого сравнения многоверсионной архитектуры СУБД тут нет.
Почему это нет? Разве на момент запуска SELECT не должен браться снимок таблицы, ведь я использую даже не

Код: Выделить всё

INSERT INTO table SELECT FROM table
а последовательный перебор в цикле в ХП.

Добавлено: 23 авг 2006, 21:51
Merlin
Lars писал(а):
kdv писал(а): и никакого сравнения многоверсионной архитектуры СУБД тут нет.
Почему это нет? Разве на момент запуска SELECT не должен браться снимок таблицы, ведь я использую даже не

Код: Выделить всё

INSERT INTO table SELECT FROM table
а последовательный перебор в цикле в ХП.
Видимостью записей заведует не оператор, а транзакция. Транзакция, независимо от уровня изоляции, всегда видит результаты своей работы. Чужой работы - в зависимости от уровня изоляции. Чтобы получить снимок на момент завершения селект, добавь в селект сортировку по какому-нибудь неиндексированному полю, тогда в процессе сортировки сначала будет сформирован в сторонке резалтсет и только потом пойдут инсёрты. Это трюк, использование особенностей implementation. Снимок на момент запуска селект получить невозможно. Можно добиться того, чтобы эти снимки были идентичны - выполнять в снапшоте и внутри этой транзакции до выполнения этого оператора эту таблицу не трогать, в смысле не модифицировать. Но это будет снимок на момент запуска транзакции.

Добавлено: 23 авг 2006, 22:23
Lars
Вообще это недочет СУБД или архитектурная задумка?

Если недочет, то почему не правится?

Добавлено: 24 авг 2006, 07:44
Dimitry Sibiryakov
То что в пределах транзакции видны ее изменения это, конечно, задумка. Нестабильность в пределах одного статемента это скорее недочет. Не правится потому что, как я написал выше, очень глубоко зарыт.

Добавлено: 24 авг 2006, 08:05
Lars
Проблема решена, ответы получены.
Думаю, что тема закрыта.
Спасибо за ответы.

Добавлено: 24 авг 2006, 10:22
kdv
я тебе посоветую почитать топик на sql.ru, где в частности я подробно описал неатомарность select в read_committed. А то там некоторые чуть ли не в обморок от этого падали :)

начиная с моего сообщения на эту тему, и дальше
http://www.sql.ru/forum/actualthread.as ... fc#1447129

или отсюда
http://www.sql.ru/forum/actualthread.as ... 73455&pg=2

Добавлено: 25 авг 2006, 10:03
dimitr
на самом деле, именно это поведение исправить несложно. Но проблема много ширше и править надо все сразу. А это уже действительно нетривиально.

Добавлено: 25 авг 2006, 10:49
Dimitry Sibiryakov
Угу, запуск селекта в отдельной транзакции... Остается всего полшага до запуска этого селекта с другим tdbb, а это уже полный ахтунг. :lol:

Добавлено: 25 авг 2006, 11:09
dimitr
решается все и без отдельных транзакций, но слишком много неочевидных нюансов и тяжело тестить. Я надеялся закончить к 2.1, но не выходит пока каменный цветок.

Добавлено: 25 авг 2006, 18:52
Lars
Dimitry Sibiryakov писал(а):Угу, запуск селекта в отдельной транзакции... Остается всего полшага до запуска этого селекта с другим tdbb, а это уже полный ахтунг. :lol:
ну а если открыть набор данных как снэпшот и дувайловским циклом проходить и добавлять? Пройдет же все в норме?

Добавлено: 25 авг 2006, 18:58
kdv
ну а если открыть набор данных как снэпшот
во-первых, что значит "открыть набор" - это ж сервер, он целым "набором" не оперирует. Во-вторых - "как снэпшот" - нет такого понятия. есть snapshot-транзакция.

Добавлено: 26 авг 2006, 10:25
Lars
Открыть набор в рамках snapshot-транзакции. Вот так именно я и хотел сказать :)

а потом его перебирать

Добавлено: 26 авг 2006, 11:03
kdv
Lars, ты ведь так и не читал тот топик на sql.ru, который я тебе посоветовал. Еще раз замечу - будут санкции.

Добавлено: 27 авг 2006, 21:36
Lars
kdv писал(а):Lars, ты ведь так и не читал тот топик на sql.ru, который я тебе посоветовал. Еще раз замечу - будут санкции.
Перечитал повторно!
И вот это имеет там смысл:
kdv писал(а): ...если нас напрягает "невоспроизводимость чтения" в read_committed, то мы должны использовать snapshot

Добавлено: 27 авг 2006, 23:01
kdv
теперь ты меня убеди, что снапшот для запроса в read-committed имеет смысл. еще раз подчеркиваю, что update ... where field in (select) к этому отношения не имеет.