![]() |
![]() |
Как правильно индексировать в 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).
См. также:

![]() |