Форум » [x]Harbour » REINDEX ... » Ответить

REINDEX ...

Andrey: Всем привет ! Не пользовался этой командой вообще. Делал закрытие индексов и создание нового индекса. А как сделать REINDEX на драйвере CDX без закрытия индексов ? Для простоты я использую один файл - один индекс. Так привык давно делать, да и удобнее по Dbsetorder() переключаться. Делаю так: [pre2] SET AUTOPEN ON USE ( cDbf ) ALIAS TEST SHARED NEW // подключается автоматом test6.cdx OrdSetFocus('ALL') Dbsetorder(1) .... // cUser := "1-user", "2-user" и т.д. cIndx := GetStartUpFolder() + "\test6." + cUser + '.cdx' DELETEFILE(cIndx) // обязательно SELECT TEST INDEX ON RECNO() TAG CODE1 TO (cIndx) FOR &cFilter ADDITIVE // условный индекс OrdSetFocus('CODE1') Dbsetorder(2) GO TOP ...[/pre2] Пытаюсь потом в программе сделать: [pre2] SELECT(oBrw:cAlias) nOrder := INDEXORD() IF nOrder == 2 // перестроить индекс REINDEX // строка 897 ENDIF[/pre2] Вылетает с ошибкой: Error DBFCDX/1023 Exclusive required: W:\HB_Project\Tsb_Basic\Demo6\test6.dbf --------------------------------- Stack Trace --------------------------------- Called from ORDLISTREBUILD(0) Called from RECNOREFRESH(897) in module: demo6.prg Called from CHANGEWINBROWSE(1037) in module: demo6.prg Called from (b)MAIN(47) in module: demo6.prg

Ответов - 26 новых, стр: 1 2 All

PSP: REINDEX Rebuild open indexes in the current work area ------------------------------------------------------------------------------ Syntax REINDEX [EVAL <lCondition>] [EVERY <nRecords>] Arguments EVAL <lCondition> specifies a condition that is evaluated either for each record processed or at the interval specified by the EVERY clause. This clause is identical to the EVAL clause of the INDEX command, but must be respecified in order for the reindexing operation to be monitored since the value of <lCondition> is transient. EVERY <nRecords> specifies a numeric expression that modifies how often EVAL is evaluated. When using EVAL, the EVERY option offers a performance enhancement by evaluating the condition for every nth record instead of evaluating each record reindexed. The EVERY keyword is ignored if no EVAL condition is specified. Description REINDEX is a database command that rebuilds all open indexes in the current work area. When the reindexing operation finishes, all rebuilt indexes remain open, order is reset to one, and the record pointer is positioned to the first record in the controlling index. If any of the indexes were created with SET UNIQUE ON, REINDEX adds only unique keys to the index. If any of the indexes were created using a FOR condition, only those key values from records matching the condition are added to the index. In a network environment, REINDEX requires EXCLUSIVE USE of the current database file. Refer to the "Network Programming" chapter in the Programming and Utilities Guide for more information. Caution! REINDEX does not recreate the header of the index file when it recreates the index. Because of this, REINDEX does not help if there is corruption of the file header. To guarantee a valid index, always use INDEX ON in place of REINDEX to rebuild damaged indexes

Dima: Andrey пишет: OrdSetFocus('CODE1') Dbsetorder(2) А на хрена ? Коли юзаешь составной индекс , то крайне "криво" юзать Dbsetorder , так как не известно каким по счету будет нужен тэг , юзай OrdSetFocus , этого достаточно. Об этом писал еще А. Кресин.

Andrey: Если открываю базу в SHARED то условный индекс всё равно могу делать в отдельном месте для каждого юзера. Мне нужно его пере индексировать. Т.е. команда REINDEX не катит. Тогда пойдём сложным путем, запоминаем открытые индексы, закрываем все индексы, восстанавливаем индексы, кроме нужного и делаем заново условную индексацию. Спасибо за разъяснения ! Dima пишет: Dbsetorder , так как не известно каким по счету будет нужен тэг , юзай OrdSetFocus , этого достаточно. Для справки в программе у меня есть отдельный показ открытых баз и всех индексов с любого окна. Мне просто надо посмотреть и всё видно - какой нужен номер Dbsetorder. Да я привык уже к этому. Переделывать много чего надо.


Pasha: dbSetOrder и так реализован через ordSetFocus. Первый из них принимает только числовой параметр индекса, а второй - и числовой, и символьный, т.е. имя тэга. Запись вида OrdSetFocus('ALL') Dbsetorder(1) эквивалентна OrdSetFocus('ALL') OrdSetFocus(1) Если All - первый тэг, то здесь два раза выполняется одна и та же операция. Номер тега в составном индексе жестко закреплен, так что к тегу можно смело обращаться как по его имени, так и по номеру. Я обычно по номеру и обращаюсь, проблем не было. Что касается индекса по условию, то, насколько я понял, индекс каждый раз перестраивается для другого условия. Не сказал бы, что это красивое решение, но сейчас не об этом. По факту это временный индекс - его построили, использовали и выбросили. Поэтому нецелесообразно держать его в общем составном индексе, лучше его формировать в отдельном индексном файле. Временный он и есть временный.

Andrey: Pasha пишет: Что касается индекса по условию, то, насколько я понял, индекс каждый раз перестраивается для другого условия. Не сказал бы, что это красивое решение, А другого решения нет. Юзер как хочет, любые списки получает и делает с ними что угодно, хоть печатает, или изменяет данный список. Сколько полей в БД находиться (или спец.список полей) по стольким и выборку (условную индексацию) юзер делает и ко мне не пристаёт !!!

ММК: Andrey пишет: А другого решения нет. Ну что Вы, Андрей . Вы точно знаете, что есть и другие решения. Просто забыли.... Вот же Вам только что написали - Pasha пишет: По факту это временный индекс - его построили, использовали и выбросили. Поэтому нецелесообразно держать его в общем составном индексе, лучше его формировать в отдельном индексном файле. Временный он и есть временный. Если на основной базе будет хотя бы один один индекс этого достаточно. И любой пользователь будет иметь свой индексный файл на своей локальной машине построенный на основе основного. Никому не мешать и не "дергать" основную базу. Ну Вы же помните, приблизительно вот так - index on &mykey to tsmy_idx for !deleted() CUSTOM ADDITIVE Т.е. - Andrey пишет: как хочет, любые списки получает и делает с ними что угодно Кстати очень удобно и наглядно для этого использовать бровс. Мне кажется этот вопрос уже обсуждался ...

Andrey: ММК пишет: Если на основной базе будет хотя бы один один индекс этого достаточно. И любой пользователь будет иметь свой индексный файл на своей локальной машине построенный на основе основного. Никому не мешать и не "дергать" основную базу. Ну Вы же помните, приблизительно вот так - index on &mykey to tsmy_idx for !deleted() CUSTOM ADDITIVE Так я и делаю. На основной базе несколько индексов, и по ним строю условный индекс. [pre2]cFilter := "RCity==1.AND.Kstreet=50 .AND ...... !deleted()" index on &mykey to tsmy_idx for &cFilter CUSTOM ADDITIVE [/pre2]

Andrey: Вопрос возник другой по базе. Нужно по условному индексу создать массив с номерами записи. На маленьких базах это происходит быстро. Если базы большие, 30 тыч.записей и больше, то тормоза... Можно ли как то ускорить этот процесс ? Сделать несколько потоков что ли или ещё как то по другому ? Вот код который у меня сейчас:[pre2] aRecno := {} aBeg := WaitWinCreateModal( 'Считываю текущий список...' ) nPokaz := INT( nRecnoAll / 100 ) // показ каждые 1% FOR nI := 1 TO nRecnoAll ORDKEYGOTO(nI) AADD( aRecno, RECNO() ) IF nI % nPokaz == 0 // выводим через XXX записей cMsg := HB_NtoS(nI)+"/"+HB_NtoS(nRecnoAll) WaitWinTimer(aBeg, cMsg) // показ окна ожидания ProcessMessages() // ОБЯЗАТЕЛЬНО ! Чтобы форма НЕ замирала ENDIF NEXT WaitWinClose(aBeg) // убить окно ожидания[/pre2]

Pasha: вместо FOR nI := 1 TO nRecnoAll ORDKEYGOTO(nI) .. NEXT используй go top while ! eof() ... skip enddo или еще проще: dbeval({|| ...})

Andrey: Pasha пишет: используй .... А мне нужно по условному индексу создать массив с номерами записи. Я помню что dbeval({|| ...}) быстрей работает. А как его прикрутить к условному индексу ?

Pasha: Andrey пишет: как его прикрутить к условному индексу ? Странный вопрос. Надо сделать этот индекс активным. Индекс ведь для этого и нужен

SergKis: Andrey пишет Я помню что dbeval({|| ...}) быстрей работает Быстрее работает цикл, блок кода отстает ~2-5 сек. на больших базах

Andrey: Pasha пишет: Странный вопрос. Надо сделать этот индекс активным. Индекс ведь для этого и нужен Так я и об этом пишу, и код привел по условному индексу обход базы. Забыл указать nRecnoAll := ORDKEYCOUNT() а далее [pre2] FOR nI := 1 TO nRecnoAll ORDKEYGOTO(nI) AADD( aRecno, RECNO() ) ..... [/pre2] Даже если сразу объявить массив [pre2] aRecno := Array(nRecnoAll) // создаём массив FOR nI := 1 TO nRecnoAll ORDKEYGOTO(nI) aRecno[nI] := RECNO() ......[/pre2] то на малых базах - до 20 тыс. считывается RECNO() где-то 10 минут, а на больших 35-55 тыс. уже по 60 минут и более. Почему так ? Как можно ускорить ?

SergKis: Andrey Pasha прямо пишет, делай[pre2] go top while ! eof() ... skip enddo [/pre2] Зачем по индексу OdrKeyGoto(nI) ? Индекс без тебя это сделает, т.е. set order to 3 go top do while ! eof() add(aRec,recno()) skip enddo

Andrey: SergKis пишет: Индекс без тебя это сделает, т.е. Теперь понял ! Спасибо !

Pasha: Andrey пишет: то на малых базах - до 20 тыс. считывается RECNO() где-то 10 минут, а на больших 35-55 тыс. уже по 60 минут и более. Почему так ? Как можно ускорить ? Может быть стоит переделать алгоритм ? Зачем в цикле по таблице загонять все номера записей в массив ? Есть же индекс, он и так дает индексно-последовательный доступ к нужным данным Считывать по часу данные - это жесть. Зачем в таком виде это нужно то ?

Andrey: Pasha пишет: Считывать по часу данные - это жесть. Зачем в таком виде это нужно то ? Вот и я о том же. Нужно переделать алгоритм. Сделал как рекомендовал и я выпал в осадок. Вот результат: кол-во записей в БД: 52411 затрачено времени: 00:00:00.448 Блин, FOR / NEXT по базе совсем не то Вот код (кому интересно) [pre2] DbSetOrder(5) nRecnoAll := ORDKEYCOUNT() aBeg := WaitWinCreateModal( 'Считываю текущий список...' ) nPokaz := INT( nRecnoAll / 100 ) // показ каждые 1% tTime := HB_DATETIME() aRecno := {} nI := 0 go top do while ! eof() AADD( aRecno, RECNO() ) skip IF nI % nPokaz == 0 // выводим через XXX записей cMsg := HB_NtoS(nI)+"/"+HB_NtoS(nRecnoAll) WaitWinTimer(aBeg, cMsg) // показ окна ожидания ProcessMessages() // ОБЯЗАТЕЛЬНО ! Чтобы форма НЕ замирала ENDIF nI++ enddo WaitWinClose(aBeg) // убить окно ожидания ? "кол-во записей в БД:", nI ? "затрачено времени:", HMG_TimeMS( HB_DATETIME() - tTime ) [/pre2] Программа просто полетела в этой менюшке.

Andrey: Сделал в другом меню обработку БД, проще алгоритм, чтение и запись по текущей базе. [pre2]кол-во записей в БД: 59120 Было раньше затрачено времени: 00:01:20.102 Стало теперь 00:00:10.502[/pre2]

MIKHAIL: Andrey пишет: кол-во записей в БД: 59120 Было раньше затрачено времени: 00:01:20.102 Стало теперь 00:00:10.502 59 тыс база не большая, и если для выборки каждый раз индекс создаешь, то по сути делаешь двойную работу. Индекс как то может помочь если по нему многократные выборки делаешь...

Pasha: Эх, было время, когда компьютеры были компьютеры, а не суперкомпьютеры, как сейчас. И если ты не оптимизируешь код - это сразу становилось заметно. А сейчас хоть оптимизируй, хоть не оптимизируй - работает одинаково. Разве что очень крутой косяк будет заметным.

SergKis: MIKHAIL пишет Индекс как то может помочь если по нему многократные выборки делаешь... У Андрея, это совместимость очень старого кода (что бы не править во всех прогах куски текстов wvt\gui). Один, динамический тэг для разных user (по именам файлов индекса каждому) и userов не так много.

MIKHAIL: Pasha пишет: хоть не оптимизируй - работает одинаково. Ну не скажите, можно заставить работать и суперкомпьютер как доисторическую черепаху... вопрос скорее в дензнаках вложенных либо в железо либо в мозги... смотря какие возможности и предпочтения.... на мой взгляд 1С яркий тому пример SergKis пишет: что бы не править во всех прогах ну судя по посту все же частично правит код, поэтому наверное проще вообще выкинуть построение индекса, если он одноразово используется... а если по нему выборки постоянно, без перестроения, тогда другое дело... Правильно нужно определить и использовать один общий постоянный индекс для всех, что бы ускорить выборку если оно того стоит...

SergKis: MIKHAIL пишет Правильно нужно определить и использовать один общий постоянный индекс для всех, что бы ускорить выборку если оно того стоит... В том то и дело, что клиент набирает из списка условий, нужные в конкретном запросе на данный момент и далее командой индекса этот запрос выполняется, можно конечно ставить scope, filter и делать выборку, но у Андрея так со времен clipper. Возможный вариант, да и код менять не надо под новую выборку - работает и устраивает его. Говорили с Андреем на эту тему.

Andrey: MIKHAIL пишет: 59 тыс база не большая, и если для выборки каждый раз индекс создаешь, то по сути делаешь двойную работу. Индекс как то может помочь если по нему многократные выборки делаешь... Кол-во записей у каждой фирмы по разному. Это средняя фирма, с кол-вом абонентов 59тыс.записей. Операция разовая, сделал и забыл. Просто привёл её в качестве примера, что код стал оптимизирован и время на операцию уменьшилось. Ранее не делал такого.

Andrey: MIKHAIL пишет: ну судя по посту все же частично правит код, поэтому наверное проще вообще выкинуть построение индекса, если он одноразово используется... а если по нему выборки постоянно, без перестроения, тогда другое дело... Правильно нужно определить и использовать один общий постоянный индекс для всех, что бы ускорить выборку если оно того стоит... Конечно код переделываю. Переполз из терминалки на МиниГуи. Ускорение работы программы заметно по базе так очень. Единственно что с окнами задержка, медленно строятся. Карточка большая и при каждом вызове постоянно строится карточка. В терминалке карточка быстрей строится. Но наверное это тоже со временем решу, строить карточку постоянную при старте задачи. Нужно 5 карточек строить, а потом показывать под разные данные. С индексами работаю по разному. Открываю базы с постоянными индексами. Например есть постоянный индекс по адресу, при выборке строю условный индекс по нему, индекс создаётся в разы быстрей. Даже на больших базах 100 тыс. записей (кол-во заявок за несколько лет) построение условного индекса без существующих индексов операция довольно быстрая на локальном компе. Поиск по разным полям базы, включая мемо-поля. Как сделать такой поиск без условного индекса - я даже не знаю. 400 полей в базе, что юзеру придёт в голову искать, даже не думаю. Есть карточка с выбором условий - ищи что хочешь и ко мне не приставай. В сетке такие операции у меня редко кто делает. В качестве примера приводил поиск по 1 млн.записей на ЛетоДБ - там по сети всё летает. https://abonent4.ru/letodb/ SergKis пишет: да и код менять не надо под новую выборку - работает и устраивает его. Не совсем правильно. Юзеров такой поиск устраивает. На другое он не согласен. Зачем тогда переделывать, работа будет невостребована и просто выкинута в мусорку.

MIKHAIL: Andrey пишет: 400 полей в базе, что юзеру придёт в голову искать, даже не думаю. Ну если правильно понял, то набор условий FOR для индекса задает сам пользователь, на основании чего строишь индекс, а затем отобранные записи добавляешь в массив данных, после чего индекс не нужен. Если так, то нет смысла строить индекс, и потом еще раз обходить его для добавления этих записей в массив. Просто сразу делай обход всей базы данных или части на основании базового индекса с тем условием что задает пользователь. В противном случае двойная работа, а то и тройная, так как добавление записи в индекс это не одна операция... Andrey пишет: код стал оптимизирован и время на операцию уменьшилось думаю без индекса скорость возрастет в 2-3 раза



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