2015-11-20 2 views
-1

Я пытаюсь прочитать данные, которые генерируются другим приложением и хранятся в файле .MDB Microsoft Office Access. Количество записей в некоторых конкретных таблицах может варьироваться от нескольких тысяч до более 10 миллионов в зависимости от размера модели (в другом приложении). Открытие всей таблицы в одном запросе может вызвать исключение из памяти в больших файлах. Поэтому я разбил таблицу на некоторые критерии и прочитал каждую часть в другом запросе. Но проблема в том, что файлы среднего размера можно читать значительно быстрее в одном запросе без каких-либо исключений.Как предотвратить исключение OutOfMemory при открытии больших файлов доступа .MDB?

Итак, я на правильном пути? Могу ли я решить проблему OutOfMemory по-другому? Можно ли выбрать одну из упомянутых стратегий (1 запрос или запрос N) в зависимости от количества записей?

Кстати, я использую стандартные компоненты ADO DelphiXE5 и Delphi. И мне нужны все данные таблицы, и не требуется присоединение к другим таблицам. Я создаю компоненты ADO по коду, и они не подключены к каким-либо визуальным средствам управления.

Edit:

Ну, кажется, что мой вопрос не достаточно ясно. Вот несколько подробностей, которые на самом деле отвечают на вопросы или предложения, высказанные в комментариях:

Этот файл .mdb не содержит настоящую базу данных; это просто структурированные данные, поэтому не записывать новые данные, никаких транзакций, не взаимодействовать с пользователем, ни сервера, ни ничего. Стороннее приложение использует файлы Access для экспорта результатов расчета. Общий размер этих файлов обычно составляет несколько сотен МБ, но они могут вырасти до 2 ГБ. Теперь мне нужно загрузить эти данные в структуру данных Delphi, прежде чем начинать мои собственные вычисления, так как нет необходимости ждать ввода-вывода во время этих вычислений.

Я не могу скомпилировать этот проект для x64, он чрезвычайно зависит от некоторых старых DLL, которые используют один и тот же менеджер памяти с основным исполняемым файлом, и их авторы никогда не выпустят версию x64. Компания еще не решила их заменить, и это не изменится в ближайшем будущем.

И, вы знаете, парни поддержки предпочитают говорить нам «исправить это», а не просить двух тысяч клиентов «купить больше памяти». Поэтому я должен быть очень скупым в использовании памяти.

Теперь мой вопрос: TADODataSet обеспечивает лучшее управление памятью для сбора такого количества данных? Есть ли какое-либо свойство, которое не позволяет DataSet извлекать все данные одновременно?

Когда я звоню ADOTable1.open, он начинает выделять память и ждет, чтобы получить всю таблицу, как и ожидалось. Но чтение всех этих записей в цикле for займет некоторое время, и нет необходимости иметь все эти данные, с другой стороны, нет необходимости хранить запись в памяти после ее прочтения, так как нет поиска в строках. Вот почему я разбил таблицу с некоторыми запросами. Теперь я хочу знать, может ли TADODataSet справиться с этим или что я делаю, это единственное решение.

+1

Всякий раз, когда кому-то нужна вся таблица, полная данных, это обычно проблема дизайна: вы должны серьезно задать вопрос, что «нужно», а не тратить свое время на технические проблемы, связанные с этими большими размерами таблиц. –

+0

Данные представляют собой результаты анализа, созданные сторонним приложением, а файл .mdb - это просто хранилище, которое оно предлагает для передачи результатов. Здесь мне нужны все данные для дальнейших математических вычислений, и мне нужно это в ОЗУ вместо HDD. Какой дизайн вы предлагаете @JanDoggen? – saastn

+0

Это будет зависеть от ваших математических вычислений. Но тогда это становится скорее вопросом статистического или количественного анализа, а затем вопросом программирования. Возможно, вы действительно не можете сломать свой набор данных, мы не можем это видеть. Мои замечания пришли больше из бизнес-приложений, где это часто случается. –

ответ

0

Я сделал некоторые попытки и ошибки и улучшил производительность чтения данных, как в использовании памяти, так и в прошедшем времени. Мой тестовый пример - таблица с более чем 5 000 000 записей. Каждая запись имеет 3 строковых поля и 8 удвоений. Нет индекса, нет первичного ключа. Для получения памяти я использовал GetProcessMemoryInfo API.

Исходное состояние

Table.Open: 33.0 s | 1,254,584 kB 
Scrolling : +INF s | I don't know. But allocated memory doesn't increase in Task Manager. 
Sum  : -  | - 

DataSet.DisableControls;

Table.Open: 33.0 s | 1,254,584 kB 
Scrolling : 13.7 s | 0 kB 
Sum  : 46.7 s | 1,254,584 kB 

DataSet.CursorLocation: = clUseServer;

Table.Open: 0.0 s | -136 kB 
Scrolling : 19.4 s | 56 kB 
Sum  : 19.4 s | -80 kB 

DataSet.LockType: = ltReadOnly;

Table.Open: 0.0 s | -144 kB 
Scrolling : 18.4 s | 0 kB 
Sum  : 18.5 s | -144 kB 

DataSet.CacheSize: = 100;

Table.Open: 0.0 s | 432 kB 
Scrolling : 11.4 s | 0 kB 
Sum  : 11.5 s | 432 kB 

Я также проверил Connection.CursorLocarion, Connection.IsolationLevel, Connection.Mode, DataSet.CursorType и DataSet.BlockReadSize, но они не сделали заметного изменения.

Я также попытался использовать TADOTable, TADOQuery и TADODataSet и в отличие от того, что сказал Джерри here в комментариях, как ADOTable и ADOQuery лучше, чем у ADODataset.

Значение, назначенное на CacheSize, должно быть определено для каждого случая, а не значения терки, приводящие к лучшим результатам.