#delphi #nexusdb
#delphi #nexusdb
Вопрос:
Я хочу прочитать все содержимое таблицы в память как можно быстрее. Я использую базу данных Nexus, но я мог бы использовать некоторые методы, которые применимы ко всем типам баз данных в Delphi.
Таблица, которую я просматриваю, содержит 60 000 записей с 20 столбцами. Итак, не такой уж большой набор данных.
Из моего профилирования я пока обнаружил следующее:
-
Прямой доступ к таблицам с помощью TnxTable осуществляется не быстрее и не медленнее, чем с помощью SQL-запроса и ‘SELECT * FROM TableName’
-
Простой процесс перебора строк без фактического чтения или копирования каких-либо данных занимает большую часть времени.
Производительность, которую я получаю, равна
- Перебор всех записей занимает 3,5 секунды
- Перебор всех записей, чтение значений и их сохранение занимает 3,7 секунды (т.е. всего на 0,2 секунды больше)
Пример моего кода
var query:TnxQuery;
begin
query.SQL.Text:='SELECT * FROM TableName';
query.Active:=True;
while not query.Eof do
query.Next;
Это занимает 3,5 секунды для таблицы с 60 000 строками.
Звучит ли такая производительность разумно? Могу ли я воспользоваться другими подходами, которые позволили бы мне быстрее считывать данные?
В настоящее время я считываю данные с сервера на том же компьютере, но в конечном итоге это может быть с другого сервера в локальной сети.
Комментарии:
1. Это само по себе занимает 3,5 с или у вас есть другие инструкции в цикле? Потому что, если вы читаете данные, вы, вероятно, делаете это с помощью FieldByName, который известен тем, что он не такой быстрый
Ответ №1:
Вы должны использовать режим BlockRead с TnxTable для оптимальной скорости чтения:
nxTable.BlockReadOptions := [gboBlobs, gboBookmarks];
//leave out gboBlobs if you want to access blobs only as needed
//leave out gboBookmarks if no bookmark support is required
nxTable.BlockReadSize := 1024*1024; //1MB
// setting block read size performs an implicit First
// while block read mode is active only calls to Next and First are allowed for navigation
try
while not nxTable.Eof do begin
// do something....
nxTable.Next;
end;
finally
nxTable.BlockReadSize := 0;
end;
Кроме того, если вам не нужно устанавливать диапазон для определенного индекса, обязательно используйте индекс последовательного доступа для максимально быстрого доступа.
Комментарии:
1. ВАУ. Общее время теперь сокращено с 3,7 секунды до 0,5 секунды. Совсем неплохо.
2. Что касается индексов; таблица будет использовать индекс по умолчанию по умолчанию, который в моем случае является индексом последовательного доступа. Поэтому я думаю, что мне не нужно ничего делать, чтобы заставить ее использовать индекс последовательного доступа.
3. До тех пор, пока вы сохраняете SAI помеченным как значение по умолчанию, а свойство IndexName пустым, тогда да, SAI будет использоваться.
4. Похоже, что этот же метод работает и с TnxQuery. Я получаю ту же производительность, используя ‘SELECT * FROM TABLENAME’, что и при использовании TnxTable.
5. Режим BlockRead работает с TnxQuery, да. Но производительность зависит от того, используете ли вы оперативный набор результатов или нет. При действительном наборе результатов выполнение запроса вернет курсор прямой таблицы, который идентичен курсору, используемому в TnxTable. Но если текущий результирующий набор отключен (или вы делаете свой запрос слишком сложным для текущего результирующего набора), то движок sql должен создать таблицу в памяти и скопировать в нее все соответствующие записи. Вы по-прежнему получите преимущество в производительности от режима BlockRead при чтении из результирующего набора, но создание этого результирующего набора займет больше времени.