Как правильно индексировать в VFP? |
> А как правильно проиндексировать?
Хм... вопрос конечно интересный. Ладно, попробую ответить.
При создании нового "не составного" индекса по умолчанию его "Название" [Name] (Tag) совпадает с "вычисляемым выражением" [Exspression] ... Однако, индекс должен быть "одно-форматным", и независим от того, как были введены значения в поля (я имею ввиду большие/маленькие буквы). Например: в поле Exspression для индекса прописываем: UPPER(MyField) или LOWER(MyField) или PROPER(MyField)...[общепринято: UPPER(MyField)]
Конечно, если гарантировано, что "записывающая программа" это предварительно всегда делает, то приведения к одному и тому же формату в индексе кажется вроде и не надо делать... Однако, тогда при формировании запроса на поиск искомый шаблон требуется предварительно приводить к тому формату, в котором данные были записаны (ведь неизвестно, что было ввидено в виде шаблона для поиска)... любое несоответствие равносильно отсутствию (недоступность для поиска) данных...
В VFP по крайней мере в 6.0 сказанное выше для индексов в случае SET COLLATE TO "RUSSIAN" делается автоматически [т.е.UPPER(MyField), если даже в Exspression явно мы это и не прописываем]... и это может приводить к проблемам :-( Другими словами, уж лучше писать явно :-)
Если база данных у Вас реляционная, а я надеюсь что это так, то должно существовать отдельное поле Primary Key для каждой таблицы, всегда содержащее только уникальные значения для своих записей (и эти значения не должны никаким образом зависеть от значений в "прикладных" полях записи). Назначения этого поля: исключительно поддержка реляционных отношений между таблицами, и в частности, для контроля так называемой реляционной "целостности данных".
Наконец, обычно, также добавляют дополнительный индекс с выражением DELETED(), чтобы доступна была Rushmore оптимизации...
Замечания относительно Rushmore оптимизации (в основном цитируя MSDN :-)
Технология основана на оптимизации доступа к данным с помощью использования стандартных VFP-индексов (idx,cdx) и способна резко повысить производительность операций обработки данных за счёт использования оперативной памяти компьютера. Способна уменьшить время выполнения многотабличных запросов если даже индекс создаётся как временный (только на время выполнения запроса).
Если кратко, то оптимизации подвержены команды, содержащие предложение FOR и когда используемые условные выражения представлены в терминах определяющих выражений индексов. В SQL командах для успешной оптимизации не требуется предварительного открытия ни таблиц ни индексов. SQL самостоятельно решает вопрос о необходимости тех или иных индексов и, если они не существуют, создаёт их временными самостоятельно.
Оптимизации отключается для:
все другие типы индексов оптимизируемы.
Для повышения производительность отключайте (SET ORDER TO 0) активные индексы у таблиц (включенные индексы вынуждают выполнять дополнительные, но никому не нужные, действия :-().
Выражения (в Exspression) типа: NOT DELETED() или DISCOUNT > 10 не оптимизируются, хотя оптимизируется например, DELETED() [т.е. INDEX ON DELETED() TAG DEL]
Обратите внимание: при наличии индекса типа: INDEX ON DELETED() TAG DEL в режиме SET DELETED ON оптимизация может быть выполнена.
Если WHERE(FOR) содержит несколько условий соединённых AND или OR, то оптимизации подвергается каждое подвыражения, ...и если нашлось хотя бы одно не оптимизируемое подвыражение при наличии оптимизируемых, то говорят о частичной оптимизации.
Оптимизация не выполняется:
Функция SYS(3054) позволяет контролировать режим оптимизации: None, Partial, Full
Обратите внимание: определяя допустима ли оптимизации в FOR-выражениях, VFP тратит некоторое время, ... и если Вам известно, что выражения не оптимизируемы, то это время можно сэкономить, отключив оптимизацию посредством параметра NOOPTIMIZE или команды SET OPTIMIZE OFF
Оптимизация производится над базовым выражением
eIndex relOp eExp
-или-
eExpr relOp eIndex
где
Однако, функции ISBLANK() и EMPTY() не оптимизируются :-(.
Например, если созданы индексы:
каждое из нижеследующих выражений оптимизируемо:
Выражение может содержать переменные или функции, вычисляемые до конечных выражений. Например, нижеследующая последовательность команд приводит к оптимизации:
STORE "WASHINGTON AVENUE" TO cVar
ADDR = cVar
ADDR = SUBSTR(cVar,8,3)
Совет: чтобы быть 100% уверенным в каждом конкретном случае используйте функцию SYS(3054) для контроля... см. также "Q156551 HOWTO: Use SYS(3054) to Optimize a Query" (http://support.microsoft.com/kb/q156551/)
> как правильно воспользоваться параметром ORDER в SELECT-SQL
Вот пример кода в версии VFP 8.0 (SP1VFP8), который как надеюсь покажет вам, что не следует использовать ключи неопределённой длины:
#DEFINE USE_PROBLEM_TAG .T. IF VERSION(5) < 800 MESSAGEBOX("Sorry, this test for VFP 8.0 (or later) only.") RETURN .F. ENDIF RAND(-1) LOCAL lcCursor as String lcCursor = "_" + SYS(2015, 2) CREATE CURSOR (lcCursor) (fld1 I, fld2 I) IF !USED(lcCursor) RETURN .F. ENDIF #IF USE_PROBLEM_TAG INDEX ON ; TRANSFORM(fld1)+'_'+TRANSFORM(fld2) ; TAG fld12 #ELSE INDEX ON ; TRANSFORM(fld1, '@L 9999999999') + TRANSFORM(fld2, '@L 9999999999') ; TAG fld12 #ENDIF LOCAL lcExact as String IF SET("Exact") = 'OFF' SET EXACT ON lcExact = 'OFF' ELSE lcExact = 'ON' ENDIF LOCAL lnTestValue as Integer lnTestValue = NewValue() INSERT INTO (lcCursor) (fld1, fld2) VALUES (lnTestValue, NewValue()) INSERT INTO (lcCursor) (fld1, fld2) VALUES (lnTestValue, NewValue()) GO TOP BROWSE NORMAL NOWAIT LOCAL lcKey as String #IF USE_PROBLEM_TAG lcKey = TRANSFORM(lnTestValue); + '_' + TRANSFORM(NewValue()) #ELSE lcKey = TRANSFORM(lnTestValue, '@L 9999999999'); + TRANSFORM(NewValue(), '@L 9999999999') #ENDIF IF SEEK(lcKey, lcCursor, 'fld12') WAIT WINDOW "*** Found not exist key: '" + lcKey + "' ?!" ELSE WAIT WINDOW "Not found key: '" + lcKey + "' !" ENDIF USE IN (lcCursor) IF SET("Exact") # lcExact SET EXACT &lcExact ENDIF FUNCTION NewValue() as Integer RETURN INT(RAND()*1000000000) ENDFUNCПопробуйте выполнить этот код и при USE_PROBLEM_TAG .F. Нужно заметить, что в VFP 9.0 (SP1VFP9) такая ошибка уже ловится на этапе выполнения: Error building key for index "name". (Error 2199).
См. также: