Как вставить 800000 записей в таблицу MS Access? - PullRequest
4 голосов
/ 06 февраля 2009

Мне нужно вставить 800000 записей в таблицу MS Access. Я использую Delphi 2007 и компоненты TAdoXxxx. Таблица содержит несколько целочисленных полей, одно поле с плавающей запятой и одно текстовое поле с одним символом. Существует первичный ключ в одном из целочисленных полей (который не является автоинкейном) и два индекса в другом целом числе и поле с плавающей запятой.

Вставка данных с использованием AdoTable.AppendRecord(...) занимает> 10 минут, что недопустимо, поскольку это происходит каждый раз, когда пользователь начинает использовать новую базу данных с программой. Я не могу предварительно заполнить таблицу, поскольку данные поступают из другой базы данных (которая не доступна через ADO).

Мне удалось получить около 1 минуты, записав записи в текстовый файл с разделителями табуляции и используя объект tAdoCommand для выполнения

insert into table (...) select * from [filename.txt] in "c:\somedir" "Text;HDR=Yes"

Но мне не нравятся накладные расходы.

Наверное, должен быть лучший путь.

EDIT:

Некоторая дополнительная информация:

  • MS Access был выбран, потому что он не требует какой-либо дополнительной установки на целевой машине (машинах), и вся база данных содержится в одном файле, который можно легко скопировать.
  • Это однопользовательское приложение.
  • Данные будут вставлены только один раз и не будут изменяться в течение всего срока службы базы данных. Тем не менее, таблица содержит одно дополнительное поле, которое используется в качестве флага для указания того, что соответствующая запись в другой базе данных была обработана пользователем.
  • Одна минута приемлема (до 3 минут тоже будет), и мое решение работает, но оно кажется мне слишком сложным, поэтому я подумал, что должен быть более простой способ сделать это.
  • После того, как данные были вставлены, производительность таблицы довольно хорошая.
  • Когда я начал планировать / реализовывать функцию программы, работающей с базой данных Access, таблица не требовалась. Это стало необходимым позже, когда заказчик запросил другую функцию. (Разве это не всегда так?)

EDIT:

Из всех ответов, которые я получил до сих пор, кажется, что у меня уже есть самый быстрый способ для вставки такого количества данных в таблицу Access. Спасибо всем, я ценю вашу помощь.

Ответы [ 16 ]

9 голосов
/ 06 февраля 2009

Поскольку вы сказали, что данные 800K записей не будут меняться в течение срока службы базы данных, я бы предложил связать текстовый файл в виде таблицы и вообще пропустить вставку.

Если вы настаиваете на том, чтобы поместить его в базу данных, то 800 000 записей в 1 минуту превышают 13 000 в секунду. Я не думаю, что вы победите это в MS Access.

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

5 голосов
/ 06 февраля 2009

Было бы быстрее без индексов. Можете ли вы добавить их после импорта?

Есть ряд предложений, которые могут заинтересовать эту тему Медленная запись на диск MSAccess

4 голосов
/ 07 февраля 2009

Как насчет пропуска текстового файла и использования ODBC или OLEDB для импорта напрямую из исходной таблицы? Это будет означать изменение вашего предложения FROM для использования имени исходной таблицы и соответствующей строки соединения в качестве части IN '' предложения FROM.

EDIT: На самом деле, я вижу, вы говорите, что исходный формат - xBase, поэтому можно использовать ISAM xBase, который является частью Jet, вместо того, чтобы нуждаться в ODBC или OLEDB. Это будет выглядеть примерно так:

INSERT INTO table (...) 
SELECT * 
FROM tablename IN 'c:\somedir\'[dBase 5.0;HDR=NO;IMEX=2;];

Возможно, вам придется настроить это - я просто взял строку подключения для связанной таблицы, указывающей на файл DBF, поэтому параметры могут немного отличаться.

3 голосов
/ 14 сентября 2010

Ваше текстовое решение кажется самым быстрым, но вы можете получить его быстрее, если бы вы могли получить предварительно выделенный MS Access размером ближе к концу. Вы можете сделать это, заполнив обычную пользовательскую базу данных, закрыв приложение (чтобы буферы сбрасывались) и выполнив ручное удаление всех записей этой большой таблицы, но не уменьшив / сжав ее.

Итак, используйте этот файл для начала реального заполнения - Access не будет запрашивать (или очень мало) дополнительного дискового пространства. Не помню, есть ли в MS Access способ автоматизировать это, но это может сильно помочь ...

3 голосов
/ 07 февраля 2009

Я бы заменил MS Access другой базой данных, и для вашей ситуации я вижу Sqlite - лучший выбор, он не требует установки на клиентском компьютере, и это очень быстрая база данных и одна из лучшее решение для встроенной базы данных.

Вы можете использовать его в Delphi двумя способами:

  1. Вы можете загрузить Dll компонента Database Engine с веб-сайта Sqlite и использовать бесплатный компонент Delphi для доступа к нему, например Компоненты Delphi SQLite или SQLite4Delphi

  2. Используйте DISQLite3 со встроенным движком, и вам не нужно распространять dll с вашим приложением, у них есть бесплатная версия; -)

если вам все еще нужно использовать MS Access, попробуйте использовать TAdoCommand напрямую с SQL-вставкой вместо использования TADOTable, что должно быть быстрее, чем с помощью TADOTable.Append;

3 голосов
/ 06 февраля 2009

Как насчет альтернативной договоренности ...

Будет ли возможность сделать копию существующего файла базы данных Access с этой таблицей, которая вам нужна, а затем просто удалить все остальные данные, кроме этой большой таблицы (не знаю, есть ли в Access эквивалент что-то вроде «усеченной таблицы» в SQL-сервере)?

2 голосов
/ 14 сентября 2010

Вы не будете импортировать 800 000 записей менее чем за минуту, как кто-то упоминал; это действительно уже быстро.

Однако вы можете пропустить раздражающий шаг перевода в текстовый файл, если вы используете правильный метод (наборы записей DAO) для выполнения вставок. См. Предыдущий вопрос, который я задал и на который ответил на StackOverflow: MS Access: Почему ADODB.Recordset.BatchUpdate намного медленнее, чем Application.ImportXML?

Не используйте INSERT INTO даже с DAO; это медленно Также не используйте ADO; это медленно Но DAO + Delphi + Recordsets + создание экземпляра COM-объекта DbEngine напрямую (а не через объект Access.Application) даст вам большую скорость.

1 голос
/ 07 февраля 2009

Я бы предварительно заполнил базу данных и передал им сам файл, а не заполнил существующую (но пустую) базу данных.

Если данные, которые необходимо заполнить, изменяют, то синхронизируйте базу данных доступа ODBC (файл MDB) на сервере с помощью небольшого кода, чтобы увидеть изменения в основной базе данных и скопировать их в базу данных доступа.

Когда пользователь запрашивает новую базу данных, заархивируйте MDB, передайте им и откройте.

Кроме того, вы можете найти код, который открывает и вставляет данные в базы данных напрямую.

Альтернативно, поочередно, вы можете найти другой формат (кроме csv), доступ к которому может импортировать быстрее.

-Adam

1 голос
/ 06 февраля 2009

Получить SQL Server Express (бесплатно) и подключиться к нему из Access из внешней таблицы. SQL Express намного быстрее, чем MS Access.

1 голос
/ 06 февраля 2009

Вы смотрите в правильном направлении с одной стороны. Использование одного оператора для массовой вставки будет быстрее, чем пытаться перебирать данные и вставлять их строка за строкой. Access, являющийся базой данных на основе файлов, будет очень медленно выполнять итеративные записи.

Проблема в том, что Access обрабатывает то, как он оптимизирует записи, и на самом деле нет никакого способа контролировать это. Вы, вероятно, достигли максимальной эффективности оператора INSERT. Для дополнительной скорости вам, вероятно, следует оценить, есть ли способ записывать 800 000 записей в базу данных при каждом запуске приложения.

...