Форум » Clipper » Работа индексов в многопользовательском режиме » Ответить

Работа индексов в многопользовательском режиме

SKA: Подскажите новичку, могут ли возникнуть какие-нибудь коллизии, если несколько пользователей будут в сети открывать базы с индексами и модифицировать данные одновременно вот таким способом: use bma02 alias b share index on str(SAW,2)+str(NP,3) to BMA02 set index to BMA02 т.е. сразу индексировать в один и тотже файл или индексный файл также работает как база в shared режиме или лучше чтоб для каждого пользователя в сети индексы создавались на локальной рабочей станции?

Ответов - 14

Andrey: Индексировать базы одновременно нельзя ! Лучше индексировать базу в монопольном режиме и одним человеком, выгоняя всех остальных из этой базы или программно или "криком-всем вон из программы". А вносить исправления в базу все могу спокойно, так как сам драйвер индекса отслеживает изменение записей.

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

gfilatov: SKA, Попробуй использовать идею из следующего кода: If !File( Path_data+"MAIN.DBF" ) DBcreate( Path_data+"MAIN.DBF", aStruct ) EndIF USE ( Path_data+"MAIN" ) ALIAS MAIN SHARED NEW If !NetErr() If !File( ( Path_data+"MAIN"+INDEXEXT() ) ) INDEX ON MAIN->NAME TO ( Path_data+"MAIN_IDX" ) DBcommit() EndIF SET INDEX TO ( Path_data+"MAIN_IDX" ) Else MsgStop("Database MAIN in use", "Please, try again") return nil EndIF


Лукашевский: Насколько я помню, базы по USE по умолчанию открываются как SHARED и указывать это явным образом не обязательно. Фрагмент MsgStop("Database MAIN in use", "Please, try again") return nil надо заменить на SET INDEX TO ( Path_data+"MAIN_IDX" ) то есть открывать индекс нужно в любом случае - был ли он уже или создан только что пользователем, - у меня в программе по крайней мере именно так и сделано - все пользователи-клиенты открывают имеющиеся на главном компе базы и индексы и спокойно с ними работают. Вносимые записи тут же (ну или по DBCOMMIT() :-) появляются в списках. С удаляемыми записями сложнее - тут нужно или периодически пересвечивать объект TBrowse или перед работой с записью проверять поиском - а есть ли она ещё в базе или уже удалена.

Петр: Лукашевский пишет: Насколько я помню, базы по USE по умолчанию открываются как SHARED и указывать это явным образом не обязательно Когда встречается команда USE без SHARED или EXCLUSIVE, базы данных открываются в соответствии с текущим состоянием SET EXCLUSIVE. По умолчанию SET EXCLUSIVE установлено в ON, т.е. все базы открываются в монопольном режиме. Лукашевский пишет: Фрагмент MsgStop("Database MAIN in use", "Please, try again") return nil надо заменить на SET INDEX TO ( Path_data+"MAIN_IDX" ) Не разобрались, ну и зачем Вам открывать индекс, если не удалось открыть базу? Лукашевский пишет: то есть открывать индекс нужно в любом случае - был ли он уже или создан только что пользователем А это правильно и gfilatov так и написал If !File( ( Path_data+"MAIN"+INDEXEXT() ) ) нет файла с индексом - создаем INDEX ON MAIN->NAME TO ( Path_data+"MAIN_IDX" ) DBcommit() EndIF SET INDEX TO ( Path_data+"MAIN_IDX" ) используем индекс в любом случае

Andrey: Народ, я с вами не согласен. Если нет индекса, то нельзя его делать, так как можно налететь на "грабли", а именно 2-станции будут создавать индекс. И кто тогда вылетит ? И создавать индекс должен кто-то ОДИН и в монопольном режиме открытия базы.

Dima: Andrey пишет: Народ, я с вами не согласен. Если нет индекса, то нельзя его делать, так как можно налететь на "грабли", а именно 2-станции будут создавать индекс. И кто тогда вылетит ? И создавать индекс должен кто-то ОДИН и в монопольном режиме открытия базы. Правильно говоришь. Тут может быть несколько подходов. 1. Например если индекса нет а он нужен то можно дальше пользователя не пускать............ 2. Можно первый раз при входе в программу (утром) проверять наличие этих самых индексов и создавать их + попутно можно делать упаковку и переиндексацию и на момент вот такого входа всех пользователей временно не пускать , пока не будет выполнен вот такой первый вход. лично я так и делаю ;) я о втором варианте.

Петр: Andrey пишет: Если нет индекса, то нельзя его делать, так как можно налететь на "грабли", а именно 2-станции будут создавать индекс. И кто тогда вылетит ? А можно и не налететь. Ведь gfilatov пишет: "Попробуй использовать идею из следующего кода". Идею, а не код. Andrey пишет: И создавать индекс должен кто-то ОДИН и в монопольном режиме открытия базы. Команда SET INDEX не требует монопольного владения БД. Насчет кто-то ОДИН и Dima пишет: Можно первый раз при входе в программу (утром) проверять наличие этих самых индексов и создавать их + попутно можно делать упаковку и переиндексацию и на момент вот такого входа всех пользователей временно не пускать Это Вы скорее об администрировании БД и здесь действительно может быть несколько подходов, и REINDEX требует SET EXCLUSIVE ON. А вообще SKA каждый раз при открытии таблицы заново ее индексировать в многопользовательском режиме это слишком, если речь конечно не идет о вновь созданной базе или создании временного индекса, который будет через несколько строчек кода удален. Действительно индексный файл также работает как база в shared режиме, так что создайте его раз и позаботьтесь о поддержании его в актуальном состоянии.

Лукашевский: Dima пишет: Тут может быть несколько подходов. 1. Например если индекса нет а он нужен то можно дальше пользователя не пускать............ 2. Можно первый раз при входе в программу (утром) проверять наличие этих самых индексов и создавать их + попутно можно делать упаковку и переиндексацию и на момент вот такого входа всех пользователей временно не пускать , пока не будет выполнен вот такой первый вход. лично я так и делаю ;) я о втором варианте. 3. Назначаем какой-нибудь комп "главным" (лучше, наверное, тот, на котором базы - индексы будут создаваться быстрее), и чтобы только он мог создавать индексы, и всех юзверей предупреждаем, что на этом компе программа должна быть запущена первой. А если индекса(ов) нет - то юзверей временно не пущать. 4. Нет индекса - открываем базу в монопольном режиме и делаем по ней индекс, потом переоткрываем в SHARED. Т.о. избавляемся от варианта попытки одновременного создания индексного файла - если базу в монополе открыть не удаётся - значит, её уже открыли в монополе и делают индекс с другого компа (станции), и тогда просто ждём, пока сделают.

Лукашевский: Петр пишет: Не разобрались, ну и зачем Вам открывать индекс, если не удалось открыть базу? Согласен, извиняюсь, просто пример от gfilatov по-моему некорректный: базу в частном случае открываем и на главном компьютере тоже, на котором собственно база и лежит, и тогда !NetErr() скорее всего выдаст абы что - впрочем, утверждать не буду, я NetErr() вообще не использую...

15 лет в cliiper : Создай индекс один раз, помести его с базой на сервере и пусть на каждой станции индексную базу цепляют так : use narod new index fam,nam,sna shared а далее используй set order to 1 или 2 или 3 Индексируй только в монопольном режиме в shared команда работать не будет. Если индекс будешь цеплять так, то никаких проблем с его актуальностью не испытаешь....

gustow: И я так (как советует 15 лет в cliiper ) тоже делаю (при сетевой проге)! Коли валяется база с индексами (которые <b>должны</b> при ней быть) где-то на файл-серваке - то слепил индекс при очередной чистке-сжатии, а юзера уж пусть приходят "на готовенькое"! Вот разве что ему приспичит какой-то для себя "лично" (типа INDEX ... FOR ...) - так и это можно разрулить ("слив" для FOR в локальную времянку и т.п. подходы). А общее - не трожь!!! И проблем с актуальностью (если своевременые COMMITы делать) тоже не возникало ни разу за мнадцать лет (всякая там забивка больничных листов, поликлиничных посещений и т.п. - станций 40-50 одновременно - аж года с 92-го до последних времен фурычила на Netware-серваке без "фатальных" завалов).

Marry: Здравствуйте! Подскажите, пожалуйста, про DBcommit() при индексировании. Выше в фрагменте: INDEX ON .. TO ... DBcommit() Это нужно для общего индекса на сервере?

AlexMyr: Marry пишет: DBcommit() Это нужно для общего индекса на сервере? Вкратце: dbcommit() служит для принудительного сброса данных с буфера на диск, во избежании пропадания данных, в сетевой среде делает видимыми данные для других процессов, к-е работают с этой базой. Если баз >1, то применяем dbcommitall(), одни раз для всех открытых баз.



полная версия страницы