Оптимизация заполнения локальной базы данных WebSQL

Я пытаюсь оптимизировать скорость, которую моя локальная база данных заполняет в разрабатываемом веб-приложении. В настоящее время он использует PHP для доступа к базе данных, а затем вставляет эти данные в локальную базу данных с помощью Javascript.

Проблема в том, что все, что больше, чем пара записей, замедляет его, и я почти уверен, что это потому, что он выполняет отдельный SQL-запрос для КАЖДОЙ строки. Я читал о транзакциях (фиксации и откаты, а что нет), и это похоже на ответ, но я не совсем уверен, как его реализовать или даже где.

Вот пример одной из функций, которая загружает конкретную таблицу.

function ploadcostcodes()
{
$IPAddress = '';
$User = '';
$Password = '';
$Database = '';
$Company  = '';
$No='';
$Name='';
ploadSQLConnection($IPAddress,$User,$Password,$Database,$Company);

// Это подключается к фактической базе данных, откуда поступает информация.

$Login = 'XXXXXXX';
$conn=mssql_connect($IPAddress,$Login,$Password);
 if (!$conn )
{
      die( print_r('Unable to connect to server', true));
}
 mssql_select_db($Database, $conn);

 $indent="        ";

$sql="SELECT Cost_Code_No as No, Description as Name, Unit_of_Measure FROM v_md_allowed_user_cost_codes WHERE Company_No = " . $Company . " and User_No = '" . $User . "'";

 $rs=mssql_query($sql);
 if (!$rs)
 {
   exit("No Data Found");
 }

 while ($row = mssql_fetch_array($rs))
 {
     $No = addslashes($row['No']);
     $Name = addslashes($row['Name']);
     $Name = str_replace("'",'`',$Name);
     $Unit = addslashes($row['Unit_of_Measure']);

  //THIS IS WHERE I SEE THE PROBLEM

     echo $indent."exeSQL(\"INSERT INTO Cost_Codes (Cost_Code_No,Name,Unit_of_Measure) VALUES('".$No."','".$Name."','".$Unit."')\",\"Loading Cost Codes...\"); \r\n";
 }
 mssql_free_result($rs);
 mssql_close($conn);
 return 0;
}

Я не знаю, для чего нужна транзакция (или даже если это то, что нужно сделать). Существует MSSQL для доступа к данным, SQLite для их вставки и Javascript для запуска PHP-кода.


person Will    schedule 05.04.2012    source источник


Ответы (1)


Я бы подготовил запрос с заполнителями, а затем выполнил бы его для каждой строки с правильными аргументами. Что-то вроде этого (только часть JS, используя underscore.js для помощников массива):

db.transaction(function(tx) {
    var q = 'INSERT INTO Cost_Codes (Cost_Code_No, Name, Unit_Of_Measure) VALUES (?, ?, ?)';
    _(rows).each(function(row) {
        tx.executeSql(q, [row.code, row.name, row.unit]);
    });
});

Изменить: запрос с заполнителями имеет два основных преимущества:

  1. Механизму БД намного проще кэшировать и повторно использовать планы запросов (поскольку вы выполняете один и тот же запрос сто раз, а не сто разных запросов один раз).
  2. Это значительно упрощает экранирование данных и избежание SQL-инъекций.
person DCoder    schedule 05.04.2012
comment
Я не понимаю использование подчеркивания в строке 3. - person Phillip Senn; 03.05.2012
comment
@Pedro: это часть underscore.js, _(array).each работает так же, как forEach, выполняет заданную функцию для каждый элемент в array. - person DCoder; 03.05.2012
comment
Что, если одна из вставок выйдет из строя, как тогда будут управляться транзакции. Поскольку каждый executeSQL является асинхронным, он может вставить другой SQL перед сбоем. Есть ли способ обойти это. - person VikrantY; 08.09.2013
comment
@VikrantY: да. Вы можете передать обратный вызов успеха и обратный вызов ошибки для каждого вызова executeSql — обратный вызов ошибки может откатить всю транзакцию. Вместо использования each вы можете создать цепочку вызовов - создать функцию, которая вырезает одну строку из rows и выполняет запрос для этой строки, обратный вызов успеха запроса вызывает ту же функцию (поэтому она повторяется до тех пор, пока rows не станет пустым) и ее вместо этого обратный вызов error откатывает транзакцию. (Обратите внимание, что ожидание выполнения каждой строки перед запуском следующей снижает скорость параллелизма. Возможны и другие решения.) - person DCoder; 08.09.2013
comment
Спасибо @DCoder. Я достиг вышеизложенного, используя JQuery Queue, чтобы сделать его проще. Но концепция именно то, что вы упомянули. Я не уверен насчет параллелизма. Я думал, что в JavaScript нет потоков, поэтому у него не было возможности делать что-то параллельно (конечно, за исключением WebWorkers). - person VikrantY; 10.09.2013
comment
Извините, вы правы, параллелизма здесь нет. Не обращайте внимания. - person DCoder; 10.09.2013
comment
К вашему сведению - если вы хотите узнать разницу в скорости с 1 транзакцией по сравнению с 1 транзакцией на запрос... Я только что протестировал оба метода с более чем 500 запросами. Я обнаружил, что на 1 транзакцию ушло около 3 секунд, по сравнению с 15 секундами при 500+ отдельных транзакциях. - person Gavin Pickin; 20.02.2015