![]() |
|
Модераторы: Akella |
![]()
|
|
| ksili |
|
||||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2069 Регистрация: 3.11.2005 Где: Красноярск Репутация: нет Всего: 17 |
Использую Firebird 2-й версии, Builder 6 и компоненты FIBPlus.
Описание проблемы: Есть таблица T_BUFFER, используемая как FIFO-буфер заявок. В неё помещаются записи (заявки). Параллельно работает несколько потоков, каждый из которых периодически смотрит в эту таблицу и, если там есть записи, выбирает самую старую (то есть вырезает - select, потом delete), и обрабатывает её. Проблема в том, что иногда (по-моему, примерно в половине случаев) заявка читается не одним, а скажем двумя потоками. То есть первый делает select, и до того как сделает delete, второй поток успевает сделать select той же записи. Ладно бы они ещё её оба обработали и всё, но при этом эта запись не удаляется ни одним их них. Я предполагаю, что это происходит из-за взаимной блокировки. Короче они друг другу мешают её удалить. В результате все потоки читают эту запись постоянно (до бесконечности), так как она остаётся самой старой и не удаляется. Надо сделать так, чтобы одна запись из T_BUFFER читалась только одним потоком. Сейчас вырезание из буфера реализовано так: есть компонент TpFIBQuery в котором выполняется delete. У этого компонента есть свойство BeforeExecute, в котором выбирается та же запись, что и удаляется. Удаляем:
Перед этим читаем в BeforeExecute():
Я вижу два пути решения проблемы: 1) Снизить вероятность одновременного чтения сократив время выполнения связки select-delete. Вот здесь хотелось бы услышать ваши советы. а) Значительно ли сократится время выполнения этих двух запросов, если их оформить в одной хранимой процедуре, а не посылать из программы? б) Тут я прочитал, что можно подготавливать запросы, чтобы при последующем их вызове серверу посылался только дескриптор запроса, а не весь запрос, что может значительно повысить быстродействие. Как это можно сделать при помощи компонентов FIBPlus? 2) Может вообще исключить возможность одновременного чтения одной записи, если использовать блокировки? Я много прочитал про транзакции в небезызвестной книге Хелен Борри, а также другие материалы в сети, но так и не понял, можно ли установить какие-то параметры транзакции, чтобы select записи блокировал эту запись (а не всю таблицу)? Если заблокировать удастся, запросы самой старой записи из других потоков просто не будут видеть эту запись и выберут самую старую из оставшихся или вообще ничего не выберут? -------------------- Ничто так не развивает аналитическое мышление, как отладка сложной программы без возможности пошагового выполнения (с) |
||||
|
|||||
| Akella |
|
||||||||
![]() Творец ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 18485 Регистрация: 14.5.2003 Где: Корусант Репутация: 20 Всего: 329 |
предлагаю добавить в таблицу поле Editing типа Integer и хранить там 0-запись не редактируется или 1-запись редактируется. Тогда для выборки можно указывать условия типа where editing <> 1 и ненужно делать delete после select, а delete можно сделать после успешного редактирования записи из таблицы-буфера Добавлено через 2 минуты и 59 секунд
нужно попробовать сделать так, чтобы в один момент времени к таблице имел доступ только один поток. Т.е. перед select устанавливаем глобальную переменную в программе, а лучше на сервере, которая скажет остальным: "курите, парни, я работаю", а после select`а изменить значение глобальной переменной, чтобы остальные потоки значи, что можно работать и так в каждом потоке. Добавлено через 6 минут и 4 секунды
разве так можно? Добавлено через 8 минут и 2 секунды
используй хранимую процедуру |
||||||||
|
|||||||||
| ksili |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2069 Регистрация: 3.11.2005 Где: Красноярск Репутация: нет Всего: 17 |
Так это же ты меня научил! http://forum.vingrad.ru/index.php?showtopi...t&p=1062480 -------------------- Ничто так не развивает аналитическое мышление, как отладка сложной программы без возможности пошагового выполнения (с) |
|||
|
||||
| Akella |
|
|||
![]() Творец ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 18485 Регистрация: 14.5.2003 Где: Корусант Репутация: 20 Всего: 329 |
Нужно учесть тот факт, что запись может остаться необработанной, т.к. ты её удаляешь из таблицы,
смотри: 1. Select 2. Delete 3. Исключение... Добавлено через 29 секунд ааа, я не увидил IN Добавлено через 4 минуты и 28 секунд попробуй вместо IN использовать EXISTS, т.е. запрос переделай на использование EXISTS - серверу немного, но полегче будет |
|||
|
||||
| ksili |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2069 Регистрация: 3.11.2005 Где: Красноярск Репутация: нет Всего: 17 |
Ок. Попробую сделать хранимку.
Идея с глобальной переменной на сервере тоже понравилась. Чтобы её сделать, надо ли создавать отдельную таблицу, поле которой будет этой самой переменной? Или уже есть какие-то служебные таблицы которые можно использовать? -------------------- Ничто так не развивает аналитическое мышление, как отладка сложной программы без возможности пошагового выполнения (с) |
|||
|
||||
| Akella |
|
|||
![]() Творец ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 18485 Регистрация: 14.5.2003 Где: Корусант Репутация: 20 Всего: 329 |
||||
|
||||
![]()
|
| Правила форума "Interbase" | |
|
|
Обязательно указание: 1. Версию InterBase (Firebird, Yaffil) 2. Способа доступа (ADO, BDE, IBX и т.д.)
Если Вам понравилась атмосфера форума, заходите к нам чаще! С Уважением, Akella. |
| 0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
| 0 Пользователей: | |
| « Предыдущая тема | Firebird, Interbase | Следующая тема » |
|
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |