Форум » Clipper » Правильность индекса! » Ответить

Правильность индекса!

Pager: Если индексный файл (Clipper 5.2E ntx) стал неактуальным (например, dbf обновили при закрытом индексе), то DbSeek() может прекрасно встать на неправильную запись и дать истину (т.е. якобы запись успешно нашлась и спозиционировалась). Нет, чтобы Клиппер проверил, соответствует ли найденная запись ключевому выражению, НО ОН ЭТОГО НЕ ДЕЛАЕТ. В результате программа встала на неправильную запись, а думает, что она - на нужной записи. Далее обновляем совершенно не ту запись и т.п. и т.п. Караул. Есть ли методика решения?

Ответов - 16

Григорьев Владимир: Я, например, такой методики не вижу. Так как работа происходит согласно дереву ключей, хранящемуся в файле NTX, то вы и получаете ту запись, которая указана в NTX.

Dima: Pager Так и должно быть :) Обновляй dbf при открытом индексе. А как иначе ? :) Clipper за тебя ни чего не будет проверять по ходу. Делай это сам. Наверное кто то базу поюзал сторонней прогой или инструментом ? На самом деле нужно запрещать такие вещи делать !!! PS Поюзали видимо с помощью access , foxpro или еще чем то..........низя это делать если важны данные в программе и результат ее работы. Руки бы пообрывал таким умельцам !!!

lista: Pager пишет: Есть ли методика решения? пробовал такую методику, где-то тащил в Инете 1. В зависимости от к-ва записей в ДБФ берем случайным образов номера записей // --- Номера записей для проверки --- AADD( aNNN, 1 ) IF ( Reccount() > 1 ) AADD( aNNN, Reccount() ) IF ( Reccount() > 2 ) AADD( aNNN, Int( RANDOM()%( Reccount()-1 ) ) + 1 ) IF ( Reccount() > 5 ) AADD( aNNN, Int( RANDOM()%( Reccount()-1 ) ) + 1 ) AADD( aNNN, Int( RANDOM()%( Reccount()-1 ) ) + 1 ) ENDIF ENDIF //> 2 ENDIF // > 1 ASORT( aNNN ) // по порядку номера aB:=&("{||"+ORDKEY()+"}" ) FOR j=1 TO Len( aNNN ) DbGoTo( aNNN[ j ] ) Value := Eval( aB )//Значение индексного выражения для этой записи Seek Value // поиск значения по индесу x:= Eval( aB ) // вычисляем уже для этой записи IF Value != x ) )// Ошибка WAIT ERROR ; "Файл "+Alias() + " Индекс N "+Str( i, 2 )+";"+ ; "индексное выражение :"+ OrdKey( i )+";"+ ; "Надо "+Substr( XTOC( Value ), 1, 60 )+";"+ ; "Есть "+Substr( XTOC( x ), 1, 60 )+";"+ ; "запись "+Str( aNNN[ j ], 7 )+";"+ ; "не соотвествует содержимому файла БД." ===== P.S. У самого давно уже выключено, т.к. смысла нет...


Dima: lista пишет: пробовал такую методику, где-то тащил в Инете у меня эта метода (ну почти она) включена по сей день на всякий пожарный , но мои пользователи сторонние проги не юзают на рабочих базах и предупреждены что могут быть глюки. По ходу эта метода не спасетPager , так как записи проверяются случайным образом а чекать все это будет большущий тормозок ! ;)

Peretsc: У нас принята такая методика : при выходе из проги всем индексам ставится дата и время, как и дбф-ам - а при входе, соответственно, проверяется... хоть один не совпал - переиндексация базы...

suv4: Pager пишет: Нет, чтобы Клиппер проверил, соответствует ли найденная запись ключевому выражению, НО ОН ЭТОГО НЕ ДЕЛАЕТ. ах-ах-ах... ну сам проверяй, кто мешает func xKeyData(Order) local i,RddName RddName:=rddname() do case case RddName of: "SIXCDX","SIXNSX" ret sx_KeyData(Order) case RddName of: "DBFNTXAX","DBFCDXAX" ret ax_KeyVal(Order) other if !empty(OrdKey()) ret &(OrdKey()) end end ret NIL Сикать так: func SeekWithCheck(Key) if dbSeek(Key) .and. xKeyData(Key) = Key // set exact == OFF ret .T. endif dbGoto(lastrec()+1) ; dbSkip() ret .F.

suv4: Peretsc пишет: У нас принята такая методика : при выходе из проги всем индексам ставится дата и время, как и дбф-ам - а при входе, соответственно, проверяется... хоть один не совпал - переиндексация базы... 1) В некоторых ОС пока файл открыт другой станцией - дату и время обновить нельзя. 2) Возникает проблема совместимости с другим софтом. Например, редактор дбф. Так же видел монстрообразные системы, которые состоят из множества отдельных EXE-модулей (половина из которых - ночные автономные процессы, которые тусуют данные). Их исходники не всегда доступны. А какие именно данные обрабатывает (даже внутри одного модуля) - зависит от расклада. То есть навесить в пакетный файл после этого модуля прописку даты-времени - проблематично. Даже если быть на 100% уверенным, что данный процесс обработает такие-то файлы - прописка даты-времени может не выполниться, т.к. параллельно работает еще один процесс (см пункт 1) 3) Работают 10 станций. Одна из них зависла, не успев прописать в индекс правильные данные. Индекс уже неверен. Остальные 8 закончили работу. Самая последняя вышла и установила дату-время индексного файла. Имеем неверный индекс с прописанной датой-временем. Все-таки seek надо проверять. Хотя (как сейчас скажут) и это не панацея без транзакций )

lista: А может нужно не бороться, не с последствиями (индекс разрушен), а с причинами разрушения!

suv4: Конечно. А SeekWithCheck - как раз и будет служить индикатором, насколько такая борьба успешна

serega: Я понимаю, как можно написать свой seek(), чтобы самому делать контроль индекса. Более того, можно даже подменить стандартный dbseek собственным, через #translate. Но это будет не так эффективно, как если бы клиппер делал это изнутри. Я думал, что может быть есть какие-то настройки и т.п. Кстати, под ADS вроде стандартный dbseek просто не находит запись и выдает .F., а вот без ADS прекрасно "находит" не ту запись и встает на нее. Значит, под ADS он всё-таки, видимо, проверяет соответствие найденной записи индексному выражению. Но к сожалению нам надо работать не только под ADS. Вот я и подумал, нет ли какой-то настроечки.

suv3: serega пишет: Но это будет не так эффективно, как если бы клиппер делал это изнутри. Замерь разницу в секундых между тысячей вызовов dbSeek и тысячей вызовов SeekWithCheck

serega: Бороться с причинами порчи индексов можно и нужно (например, не открывать без индексов и т.п.). Но всё это может лишь уменьшить вероятность порчи индекса. Индекс может испортиться по 1000 причинам, среди которых самая банальная - это любой сбой (хоть отключение питания) в момент корректировки (и даже вне момента корректировки, если данные задержались в сети, что тоже может быть по 1000 причинам).

serega: Не замерял, но тут важно, в сети это или на локале. Кроме того, неприятно, что приходится использовать макро (&). Думаю, это всё-таки должно увеличить время, особенно для сложных индексных выражений. Но, с другой стороны, это видимо единственный трезвый выход и его надо взять на вооружение. Если только у клиппера всё же нет какой-то настроечки (т.к. изнутри клиппера это было бы сделать совершенно естественно и разумно). По поводу выборочной проверки индексов (это предлагалось выше): есть это у меня, но мало спасает. На файлах с 500 000 записей выборка в 500 записей - это очень непредставительно, а больше - жаль траты времени.

p519446: Чтобы индексы перестали "слетать", надо устранить первопричину этого: обработку этих индексов на клиентских машинах. А для этого надо приложение переписать под АДС. Когда я сделал это, то забыл об этой проблеме. Индексы пришлось перестраивать только один раз за прошедший год, и то - сам был виноват (перетряхивал в аврале .dbf-ники без индексов и забыл их после перестроить).

suv4: serega пишет: неприятно, что приходится использовать макро (&). жаль траты времени. еще раз. замерь время! получи разницу во времени. она будет измеряться долями секунды страшные сказки о тормозах & были актуальны на IBM-PC 8086 с частотой 4мегагерца сейчас гигагерцы слава богу. дополнительное вычисление &ordkey() при seek даст замедление, которое можно замерить лишь секундомером в цикле из 1000 повторений. На глаз - неощутимо

AM: Pager пишет: Нет, чтобы Клиппер проверил, соответствует ли найденная запись ключевому выражению, НО ОН ЭТОГО НЕ ДЕЛАЕТ. Вообще-то это логично, что не проверяется без специальных указаний, т.к. на это тратится время. Конечно, для одиночных поисков без разницы, но если большую базу лопатить как следует - разница заметна. Я когда-то проверял на Клиппере 5.01 - при dbSeek() .dbf вообще не читается (требовался хитрый поиск в цикле, где полезной информацией после dbSeek был номер записи, и читать .dbf требовалось только в самом конце). А ведь .ntx обычно на порядок меньше .dbf, так что на скорость влияет (при миллионах записей). А насчёт переиндексации - я делал в своё время так: для каждого .dbf указывал, какие .ntx c ним связаны, и при несоответствии даты-времени (а также при отсутствии .ntx) переиндексируется всё, правда, надо учитывать, что .ntx может не меняться при изменении неключевого поля.



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