2009-05-08 2 views
2

Я использую DBExpress в Delphi 2007 для подключения к серверу базы данных MySQL5 в сети.Delphi - TSQLQuery, оставляющий возможность для MySQL даже после освобождения

Все работает нормально, пока я не попытаюсь загрузить большое количество данных. Я пытаюсь вставить 8000+ записей в базу данных, по одному в цикле, в цикле я передаю объект TSQLConection функции вместе с данными, которые нужно вставить.

Функция создает объект TSQLQuery и запускает запрос вставки, прежде чем освобождать TSQLQuery. когда я запускаю его на больших наборах данных, я получаю сообщения о том, что сервер MySQL имеет множество соединений. Я вижу это в списке процессов для сервера MySQL.

+---------+------+-------------------------------+--------+---------+------+--------+-----------------------+ 
| Id  | User | Host       | db  | Command | Time | State | Info     | 
+---------+------+-------------------------------+--------+---------+------+--------+-----------------------+ 
| 2962500 | name | myispdomain.co.uk:27812  | data | Sleep | 3 |  | [NULL]    | 
+---------+------+-------------------------------+--------+---------+------+--------+-----------------------+ 

Существует один entriy для каждого объекта TSQLQuery я создал, и если я пошагово код, который я могу увидеть новый один идти, когда я бегу ExecSQL(). Я вызываю FreeAndNil в TSQLQuery и пытаюсь позвонить Close перед его освобождением.

Мои настройки соединения MySQL являются

ConnectionName := 'MySQLConnection'; 
    DriverName  := 'MySQL'; 
    GetDriverFunc := 'getSQLDriverMYSQL'; 
    KeepConnection := TRUE; 
    LibraryName := 'dbxmys30.dll'; 
    LoadParamsOnConnect := False ; 
    LoginPrompt := FALSE; 
    Name := 'mySQLConnection'; 
    VendorLib := 'LIBMYSQL.DLL'; 
    TableScope := [tsTable,tsView]; 

    Params.Add('DriverName=MySQL'); 
    Params.Add('HostName=www.sample.com'); 
    Params.Add('Database=data'); 
    Params.Add('User_Name=myuser'); 
    Params.Add('Password=mypassword'); 
    Params.Add('BlobSize=-1'); 
    Params.Add('ErrorResourceFile='); 
    Params.Add('LocaleCode=0000'); 
    Params.Add('Compressed=False'); 
    Params.Add('Encrypted=True'); 

Если установить KeepConnection Ложь проблема уходит, но время для запуска запросов идет вверх.

Есть ли способ обойти это?

+0

Вы пробовали обернуть ваши вставки в транзакцию? который должен требовать только одного соединения и должен исправить ваши проблемы с скоростью. -don –

+0

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

+0

@ Re0sless вам удалось решить проблему? Если да, то как? У меня такая же проблема. –

ответ

3

Не воссоздавайте свое соединение снова и снова, ни ваш запрос. Использовать параметры для запроса; открыть соединение один раз, заполнить параметры запроса, выполнить его, закрыть запрос (но не соединение), снова заполнить параметры запроса и выполнить его снова.

Что-то вроде этого (с использованием базы данных Advantage сервер, но концепция та же):

// Both Create() calls should be followed by try..finally to ensure they're 
// cleaned up after. Omitted for brevity. 
Conn := TAdsConnection.Create(nil); 
// Configure connection parameters here 
Conn.Open; 

Qry := TAdsQuery.Create(nil); 
Qry.AdsConnection := Conn; 
Qry.SQL.Add('INSERT INTO SOMETABLE (COL1, COL2, COL3)'); 
Qry.SQL.Add('VALUES (:COL1, :COL2, :COL3)'); 
while not OtherTable.Eof do 
begin 
    Qry.ParamByName('COL1').AsInteger := OtherTable.FieldByName('COL1').AsInteger; 
    Qry.ParamByName('COL2').AsString := OtherTable.FieldByName('COL2').AsString; 
    Qry.ParamByName('COL3').AsDateTime := OtherTable.FieldByName('COL3').AsDateTime; 
    Qry.ExecSQL; 
    Qry.Close; 
    OtherTable.Next; 
end; 
// Free query 
Conn.Close; 
// Free connection. 
1

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

1

вы можете построить большую вставку, что-то вроде:

Qry := TAdsQuery.Create(nil); 
Qry.AdsConnection := Conn; 
String qry = "INSERT INTO SOMETABLE (COL1, COL2, COL3)"; 
String values = ""; 

while not OtherTable.Eof do 
begin 
    values += "('" + OtherTable.FieldByName('COL1').AsString + 
      "','" + OtherTable.FieldByName('COL1').AsString + 
      "','" + OtherTable.FieldByName('COL1').AsString + 
      "'),"; 
    OtherTable.Next; 
end; 

//to remove last ',' and add query terminator ";" 
values = values.SubString(0, values.Length()-1) + ";"; 

qry = qry + values; //build the bulk insert 

Qry.Add(qry); 
Qry.ExecSQL; 
//Qry.Close() no need of this, exec executes the command and leave, theres nothing to close 
// Free query 
Conn.Close; 

заявление вставки должно выглядеть например: Значения INSERT INTO (col1, col2, col3) ('val1', 'val2', 'val3'), ('val1', 'val2', 'val3'), ('val1', 'val2', 'val3'), ..., ('val1', 'val2', 'val3');

С этим, как и предложение Кена, вы используете только одно соединение, но ваше приложение работает быстрее, так как вы вставляете больше данных в один запрос.

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

В настоящее время я использую этот подход со вставками из 1000 строк (с 4 по 8 столбцов данных) без проблем, я тестирую его на 5000 строк, но исключаю «потерянное соединение во время запроса», поэтому я оставил его в 1000 ,Я думаю, что при настройке сервера вы можете увеличить передачу данных, предполагая, что компонент не проблема, в моем случае 1000 его достаточно.

наконец, им с помощью Builder C не ++ Delphi, так что код я отправляю может иметь ошибки

-Jose

1

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

команда --->сон означает, что вы подключены к базе данных, но не запроса (TSQLQuery и т.д.) работает в настоящее время. На самом деле, если вы не создаете большую нагрузку, скорее всего, вы больше ничего не увидите, кроме «sleep».

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