2009-02-06 2 views
4

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

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

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

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

Но я не люблю накладные расходы этого.

Должен быть лучший способ, я думаю.

EDIT:

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

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

EDIT:

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

+0

Как быстро вам это нужно? Похоже, вы получили это как можно быстрее, учитывая, что это заняло 10 минут, и теперь требуется только 1 – Eppz

+0

. 1 минута кажется очень приемлемой для вставки 800000 записей. –

+0

1 минута вполне приемлема, но я бы хотел уйти, не создавая этот текстовый файл. – dummzeuch

ответ

3

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

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

+0

Интересная идея. К сожалению, это не сработает для меня, потому что я понятия не имею, насколько велика эта таблица (800000 записей - это тестовый сценарий, который я использовал, фактический размер зависит от содержимого другой таблицы, которая недоступна, когда db доступа .) Может быть, я сделаю несколько тестов, чтобы увидеть, следует ли их заполнять, например 500000 записей ускоряет более поздний импорт достаточно значительно, чтобы сделать его полезным. – dummzeuch

+0

Мой опыт работы с SQLServer, но другие db-модули (например, Firebird) не могут автоматически сжимать dbfiles по той же самой причине: избегая при необходимости запрашивать выделение дискового пространства для базовой ОС. Даже операция восстановления в SQLServer работает с предварительным распределением дискового пространства. –

+0

Какое улучшение вы получили, dummzeuch? –

5

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

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

+0

Да, я подумал об этом, но некоторые испытания на самом деле не показали значительного улучшения производительности. – dummzeuch

+0

Эта ссылка была интересной, спасибо. – dummzeuch

1

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

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

+0

OP сказал, что это происходит только тогда, когда пользователь создает новую базу данных, причем не каждый раз, когда приложение запускается. Это было бы проблемой :) –

+0

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

1

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

+0

Это не вариант в этом случае. – dummzeuch

+1

Получите SQL Server встроенный - не требуется установка, просто DLL. STIL La LOT лучше, чем Access. – TomTom

9

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

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

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

+1

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

+0

Сколько времени требуется, чтобы просто импортировать текстовый файл в виде таблицы (т. Е. Не вставлять его в любом месте, просто импортировать его как есть?) – JosephStyons

0

Возможно, вы можете открыть набор записей ADO для таблицы с режимом блокировки adLockBatchOptimistic и CursorLocation adUseClient, записать все данные в набор записей, затем выполнить пакетное обновление (rs.UpdateBatch).

3

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

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

+0

Если это не так, то по крайней мере «удалить * из таблицы» должно работать –

0

Также проверьте, сколько времени требуется, чтобы скопировать файл. Это будет нижняя граница того, как быстро вы можете записывать данные. В db, как SQL, обычно требуется утилита для массовой загрузки, чтобы приблизиться к этой скорости. Насколько мне известно, MS никогда не создавала инструмент для прямого доступа к таблицам MS Access, как это делает bcp. Специализированные инструменты ETL также будут оптимизировать некоторые шаги, связанные с вставкой, например, как SSIS делает преобразования в памяти, DTS также имеет некоторые оптимизации.

1

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

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

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

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

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

-Adam

+0

Хм, ваше последнее предложение заставило меня подумать: в настоящее время другая база данных - это dbase, и я думаю, что ADO также может читать dbase, чтобы я мог фактически использовать эту оригинальную таблицу в инструкции insert ... – dummzeuch

+0

Мне кажется, больше похоже на исходные данные, которые не меняются вообще. Если да, то ваш лучший вариант, я думаю, будет записывать данные в файл доступа db один раз, а затем просто копировать файл, когда пользователю нужна «новая» база данных. – pfunk

+0

Нет, это не вариант. Доступ к db будет создан в соответствии с пользовательскими настройками. Единственная вещь, которая всегда будет в этой базе данных, - это таблица. Кроме того, существует несколько основных баз данных, и мне нужно скопировать из того, который активен, когда пользователь начинает использовать db доступа. – dummzeuch

0

Если это идет от DBase, вы можете просто скопировать данные и индексные файлы и прикрепить непосредственно без загрузки? Должно быть довольно эффективно (от людей, которые приносят вам FoxPro.) Я предполагаю, что он также будет использовать существующие индексы.

По крайней мере, это должен быть довольно эффективный импорт одной команды.

+0

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

4

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

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

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

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

+0

Это может быть возможно, но для этого потребуется довольно уродливый редизайн модуля (который в настоящее время не знает об исходной таблице, но имеет только интерфейс для получения данных). Завтра я это проверю. – dummzeuch

+0

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

0

Сколько стоит 800 000 записей от одного творения к другому? Можно ли предварительно заполнить записи, а затем просто обновить те, которые были изменены во внешней базе данных при создании новой базы данных?

Это может позволить вам быстрее создать новый файл базы данных.

+0

Все эти записи могут измениться, поскольку возможно (даже вероятно), что пользователь переключился на другую основную базу данных. – dummzeuch

3

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

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

  1. Вы можете скачать Dll двигателя базы данных с Sqlite сайта и использовать компонент Free Delphi для доступа к нему, как Delphi SQLite components или SQLite4Delphi

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

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

+0

К сожалению, замена Access на данный момент в проекте не является опцией – dummzeuch

+0

Кроме того, вы уверены, что это ускорит импорт записей? –

0

Как быстро поворачивается ваш диск? Если это 7200 об/мин, то 800 000 строк за 3 минуты по-прежнему составляют 37 строк на оборот диска. Я не думаю, что вы сделаете гораздо лучше.

Между тем, если целью является оптимизация процесса, как насчет ссылки на таблицу?

Вы говорите, что вы не можете получить доступ к исходной базе данных через ADO. Можете ли вы настроить ссылку таблицы в MS Access на таблицу или представление в исходной базе данных? Затем простой запрос append из ссылки на таблицу скопировал бы данные из исходной базы данных в целевую базу данных для вас. Я не уверен, но я думаю, что это будет довольно быстро.

Если вы не можете настроить ссылку на таблицу до выполнения, возможно, вы могли бы программно создать ссылку на таблицу через ADO, а затем запрограммировать запрос добавления, а затем вызвать запрос append.

+0

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

-3

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

2

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

Вы можете пропустить раздражающий шаг перевода к тексту, однако, если вы используете правильный метод (DAO recordsets) для выполнения вставок. См. Предыдущий вопрос, который я задал, и ответил на StackOverflow: MS Access: Why is ADODB.Recordset.BatchUpdate so much slower than Application.ImportXML?

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

+0

Интересный подход. Я попробую позже (эта программа уже отправлена ​​с методом импорта текстового файла). – dummzeuch

Смежные вопросы