Промежуточный commit

Запросы, планы, оптимизация запросов, ...

Модераторы: kdv, CyberMax

Kyarginski
Сообщения: 36
Зарегистрирован: 12 дек 2006, 12:59

Промежуточный commit

Сообщение Kyarginski » 12 дек 2006, 13:15

Добрый день!

Подскажите, добрые люди!

Есть хранимая процедура:

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

CREATE PROCEDURE My_Proc
as
  declare P_MY_FLD varchar(20);
begin
         FOR
           SELECT MY_FLD
           FROM MY_TAB
           INTO :P_MY_FLD
         DO
         BEGIN
             execute procedure MY_OTHER_Proc(:P_MY_FLD);
             [b]COMMIT;[/b]
         END

end
Могу ли я поставить COMMIT в указанном месте?
Компилятор не позволяет... :(

Хочется подтверждать каждое действие...

Подскажите решение!!!

Версия сервера FireBird 2.0

adima
Сообщения: 12
Зарегистрирован: 06 сен 2005, 16:16

Re: Промежуточный commit

Сообщение adima » 12 дек 2006, 13:20

Kyarginski писал(а):Могу ли я поставить COMMIT в указанном месте?
Компилятор не позволяет... :(

Хочется подтверждать каждое действие...

Подскажите решение!!!

Версия сервера FireBird 2.0
транзакциями управляет клиентское приложение, в хранимой процедуре на сервере это невозможно

Kyarginski
Сообщения: 36
Зарегистрирован: 12 дек 2006, 12:59

Сообщение Kyarginski » 12 дек 2006, 13:24

Спасибо за оперативный ответ!
транзакциями управляет клиентское приложение, в хранимой процедуре на сервере это невозможно
Печально... :(
Совсем совсем ничего нельзя сделать?

Дергать с клиента эту процедуру?

kdv
Forum Admin
Сообщения: 6595
Зарегистрирован: 25 окт 2004, 18:07

Сообщение kdv » 12 дек 2006, 14:41

Совсем совсем ничего нельзя сделать?
видишь-ли, процедура относится к операторам SQL, поэтому как таковая она и так атомарна. Вызов commit/rollback на сервере это неправильная идея.
Дергать с клиента эту процедуру?
а как ее еще можно вызвать???

Kyarginski
Сообщения: 36
Зарегистрирован: 12 дек 2006, 12:59

Сообщение Kyarginski » 12 дек 2006, 14:47

а как ее еще можно вызвать???
Ну...
По аналогии с, например, Oracle , хочется вызвать внутри SQL-блока и подтверждать изменения через тысячу записей...

Oracle commit воспринимает более благосклонно. ;-)

WildSery
Заслуженный разработчик
Сообщения: 1738
Зарегистрирован: 05 июн 2006, 16:19

Сообщение WildSery » 12 дек 2006, 14:51

Kyarginski писал(а):хочется вызвать внутри SQL-блока и подтверждать изменения через тысячу записей...
Для каждой задачи есть несколько вариантов решения. Не упирайся в одну-единственную найденную и показавшуюся удобной возможность.
И в оракуле с такой постановкой задачи с консерваторией в первую очередь разбираться надо.

Kyarginski
Сообщения: 36
Зарегистрирован: 12 дек 2006, 12:59

Сообщение Kyarginski » 12 дек 2006, 15:06

ОК.
Спсиба :)
Думать буду!

P.S. А какие ещё возможности в данном случае существуют?

Тогда опишу изначальную задачу...
Может быть подскажите оптимальный вариант решения для FireBird.

Есть БД ~ 4 млн. записей.
Необходимо:
  • - сгруппировать записи по определенному полю
    - оставить в БД запись с максимальной датой (остальные удалить)
решение "в лоб" написанием селекта с group by по полю и одновременным удалением - работает безбожно долго (да конца не дождался...)

Что посоветуете?

Kyarginski
Сообщения: 36
Зарегистрирован: 12 дек 2006, 12:59

Сообщение Kyarginski » 12 дек 2006, 16:50

Мда...

Идей никаких?

WildSery
Заслуженный разработчик
Сообщения: 1738
Зарегистрирован: 05 июн 2006, 16:19

Сообщение WildSery » 12 дек 2006, 17:02

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

delete from Table1
  where aDate not in (select max(aDate) from Table1 group by GroupField)
Единственно, что неясно - какое отношение эта задача имеет к первоначальному вопросу?

Kyarginski
Сообщения: 36
Зарегистрирован: 12 дек 2006, 12:59

Сообщение Kyarginski » 12 дек 2006, 17:25

Единственно, что неясно - какое отношение эта задача имеет к первоначальному вопросу?
Самое прямое... :-)

Подобный запрос не дорабатывал до конца (работал почти сутки)

Захотелось выполнить задачу по частям!
Для этого и понадобился промежуточный COMMIT.
delete from Table1
where aDate not in (select max(aDate) from Table1 group by GroupField)
Кстати, тоже не корректный запрос!
Он же удалит все данные кроме максимальной aDate, не взирая на GroupField?!

Надо примерно следующее
delete FROM Table1 T1 WHERE
EXISTS
(SELECT 1 FROM Table1 T2 WHERE
(T2.GroupField = T1.GroupField) AND
(T2.aDate < (SELECT max(aDATE) FROM Table1 T3 WHERE
(T2.GroupField = T3.GroupField)
)))
Во как! 8)

Merlin
Динозавр IB/FB
Сообщения: 1502
Зарегистрирован: 27 окт 2004, 11:44

Сообщение Merlin » 12 дек 2006, 18:43

На мой взгляд, запрос без связки по ID несколько рискованный. И не самый быстрый. Я бы не морщил моск и вынес бы группировку во внешний цикл, хоть в SP хоть на клиенте, а удалял бы внутри по ID. Когда речь идёт об умирании запросов на каких-то 4-х лимонах, то это однозначно говорит о хреновых планах на хреновых индексах. Не обязательно хреновых по жизни, а хреновых для этого запроса. Типа

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

select count(*)
from sebgup_arc
COUNT
===========

4030740

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

select count (distinct code)
from sebgup_arc
COUNT
===========

2118


а теперь группировка с полным фетчем:

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

select count(*), code
from sebgup_arc
group by code
PLAN (SEBGUP_ARC ORDER SEBGUPA_SPR)

Elapsed time= 568.33 sec

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

select count(*), code+0
from sebgup_arc
group by 2
PLAN (SEBGUP_ARC NATURAL)

Elapsed time= 16.01 sec

Этому компу уже года 4. Если нужно отфетчить весь результат сортировки/группировки, то натурал выиграет всегда и тем больше, чем больше её объём. А вот если надо быстро отфетчить первый десяток строк, а дальше трава не расти - то обычно (когда индекс не по полю да/нет) наоборот.

WildSery
Заслуженный разработчик
Сообщения: 1738
Зарегистрирован: 05 июн 2006, 16:19

Сообщение WildSery » 12 дек 2006, 18:48

Да, это я чего-то заработался. Запрос построил не для даты, а для ID.
В том смысле, что оно уникально.
Вообще, если это штатная команда, я бы в процедуру забил, и вызывал процедуру.

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

create procedure KillAllExceptMaxDate
as
declare variable aDate timestamp;
declare variable GroupField <type>;
begin
  for select max(aDate), GroupField
    from Table1
    group by GroupField
    into aDate, GroupField
  do
    delete from Table1
      where GroupField = :GroupField and aDate < :aDate;
end;

Kyarginski
Сообщения: 36
Зарегистрирован: 12 дек 2006, 12:59

Сообщение Kyarginski » 13 дек 2006, 09:38

O!
Спасибо за советы!

Сначала попробовал процедуру по аналогии с KillAllExceptMaxDate.

6 часов - никаких результатов... :(
Или ещё ждать?
И сколько?

Может быть попробовать сделать
select max(aDate), GroupField||''
from Table1
group by GroupField
into aDate, GroupField
?
Как Вы думаете, поможет?


P.S. Небольшие уточнение
- Таблица БОЛЬШАЯ;
- из таблицы будут проводиться только SELECT'ы;
- добавления очень-очень редко (или никогда);
- созданы индексы по ВСЕМ полям (для сортировки на клиенте по выбранному полю в гриде);

Индексы могут мешать выборке?
"Плохие" индексы и т.п. ?

Dimitry Sibiryakov
Заслуженный разработчик
Сообщения: 1436
Зарегистрирован: 15 сен 2005, 09:05

Сообщение Dimitry Sibiryakov » 13 дек 2006, 09:49

Kyarginski писал(а): - созданы индексы по ВСЕМ полям (для сортировки на клиенте по выбранному полю в гриде);

Индексы могут мешать выборке?
"Плохие" индексы и т.п. ?
Да ты, я смотрю, с Парадокса рухнул. Лишние индексы могут помешать всему (и в твоем случае - мешают). Самое смешное, что для "сортировки на клиенте" они тоже совсем не нужны.
Дропни все индексы какие сможешь и повтори операцию. Удаление должно пройти максимум за пару минут.

WildSery
Заслуженный разработчик
Сообщения: 1738
Зарегистрирован: 05 июн 2006, 16:19

Сообщение WildSery » 13 дек 2006, 10:51

[quote="Kyarginski"][/quote]Иногда индекс может и помочь.
Но не в случае, когда ты делаешь запрос по всем данным таблицы.
Покажи статистику по индексу по полю группировки.

Kyarginski
Сообщения: 36
Зарегистрирован: 12 дек 2006, 12:59

Сообщение Kyarginski » 13 дек 2006, 10:57

Покажи статистику по индексу по полю группировки.
Глупый вопрос: :oops:
А как это сделать?

Kyarginski
Сообщения: 36
Зарегистрирован: 12 дек 2006, 12:59

Сообщение Kyarginski » 13 дек 2006, 11:04

В IBExpert'e в таблице напротив индекса с полем, по которому идёт группировка в колонке Статистика стоит число 0.00000016647.

Как ещё статистику посмотреть?

WildSery
Заслуженный разработчик
Сообщения: 1738
Зарегистрирован: 05 июн 2006, 16:19

Сообщение WildSery » 13 дек 2006, 11:13

Kyarginski писал(а):В IBExpert'e в таблице напротив индекса с полем, по которому идёт группировка в колонке Статистика стоит число 0.00000016647.
Там ещё можно ткнуть "пересчитать статистику".
Что ж ты говоришь, что у тебя около 4 млн. записей, если у тебя только по _группировочному_ полю 6 млн. уникальных значений?

Kyarginski
Сообщения: 36
Зарегистрирован: 12 дек 2006, 12:59

Сообщение Kyarginski » 13 дек 2006, 11:17

Сорри...
Это я про тестовую БД говорил... 4 млн.
А на рабочей все 15 будет :roll:

P.S. На тестовой тоже долго удаляет

Dimitry Sibiryakov
Заслуженный разработчик
Сообщения: 1436
Зарегистрирован: 15 сен 2005, 09:05

Сообщение Dimitry Sibiryakov » 13 дек 2006, 12:54

WildSery писал(а):Покажи статистику по индексу по полю группировки.
Да этот-то индекс скорее всего ерунда, а вот представь как напрягается сервер перестраивая хотя бы десяток индексов (или сколько там у него полей). Да еще я не удивлюсь, если автор создал еще по индексу в дубль к PK и FK.

Ответить