【发布时间】:2014-11-05 14:34:23
【问题描述】:
我正在使用下面的脚本将一个大的 csv 文件导入我的数据库。
如果表为空,则在本地计算机上完成该过程大约需要 5 分钟。
如果我使用该文件更新同一张表上的现有值,则需要 15 分钟以上才能完成。
我的 csv 文件包含大约 35,000 行。
我怎样才能加快这个过程?
if ( $request->get( $_POST["action"] ) == "import" ) {
$file = $upload->file_upload( "import", "media/import" );
if ( file_exists( DIR_UPLOAD_PHOTO . "/media/import/" . $file ) ) {
$file = DIR_UPLOAD_PHOTO . "/media/import/" . $file;
$handle = fopen( $file, "r" );
if ( $handle ) {
$lines = explode( "\r", fread( $handle, filesize( $file ) ) );
}
$total_array = count( $array );
$x = 0;
foreach ( $lines as $line ) {
if ( $x >= 1 ) {
$data = explode( "|", $line );
$titlu = trim( addslashes( $data[0] ) );
$alias = $this->generate_seo_link( $titlu );
$gramaj = trim( $data[1] );
$greutate = trim( $data[2] );
$pret_total = trim( $data[3] );
$pret_redus = trim( $data[4] );
$poza = trim( $data[5] );
$pret_unitar = trim( $data[6] );
$categorie = trim( $data[7] );
$brand = trim( addslashes( $data[8] ) );
$descriere = trim( addslashes( $data[9] ) );
$vizibil = trim( $data[10] );
$cod = trim( $data[11] );
$nou = trim( $data[12] );
$cant_variabila = trim( $data[13] );
$congelat = trim( $data[14] );
$tva = trim( $data[15] );
$stoc = trim( $data[16] );
if ( $cod != "" && $cod != " " ) {
$verificare = $database->select( "SELECT alias FROM produse WHERE alias LIKE '%" . $alias . "%'" );
for ( $i = 0; $i < $database->countRows(); $i++ ) {
if ( $alias == $verificare['alias'][$i] ) {
$alias = $this->increment_string( $alias, '_', 1 );
} else {
$alias = $alias;
}
}
$database->insert( sprintf( "insert into produse set
titlu='%s',
alias='%s',
gramaj='%s',
greutate='%s',
prettotal='%s',
pretredus='%s',
poza='%s',
pretunitar='%s',
categorie='%d',
brand='%s',
descriere='%s',
vizibil='%d',
cod='%s',
nou='%d',
cant_variabila='%d',
congelat = '%d',
tva = '%s',
stoc = '%d'
on duplicate key update
titlu='%s',
gramaj='%s',
greutate='%s',
prettotal='%s',
pretredus='%s',
poza='%s',
pretunitar='%s',
categorie='%d',
brand='%s',
descriere='%s',
vizibil='%d',
cod='%s',
nou='%d',
cant_variabila='%d',
congelat = '%d',
tva='%s',
stoc= '%d'",
$titlu, $alias,
$gramaj, $greutate, $pret_total, $pret_redus, $poza, $pret_unitar, $categorie,
$brand, $descriere, $vizibil, $cod, $nou, $cant_variabila, $congelat,
$tva, $stoc,
$titlu, $gramaj, $greutate,
$pret_total, $pret_redus, $poza, $pret_unitar, $categorie, $brand, $descriere,
$vizibil, $cod, $nou, $cant_variabila, $congelat, $tva, $stoc ) );
}
}
$x++;
}
}
}
这是我的递增函数
function increment_string($str, $separator = '-', $first = 1){
preg_match('/(.+)'.$separator.'([0-9]+)$/', $str, $match);
return isset($match[2]) ? $match[1].$separator.($match[2] + 1) : $str.$separator.$first;
}
【问题讨论】:
-
codereview 可能比 stackoverflow 更多
-
这可能是由于每次插入都必须检查和更新索引。您可以使用EXPLAIN 来查看在插入期间使用了哪些索引(如果有)。
-
@JayBlanchard - 为什么要在插入时使用索引?为什么人们会立即认为每个数据库减速都可以通过索引来解决。这里的问题是可用的 I/O 操作有限。机械驱动器每秒可以压缩 300 个 I/O。这意味着每秒 300 个查询。如果这些查询是对 MULTIPLE 查询进行分组的事务,则可以有效地使用 HDD 带宽。基本上,强制磁盘在单个 I/O 中刷新 500 个查询会加快速度。这与索引无关。
-
根据我的经验@N.B.我们已经在像这样的 INSERT 操作的大型数据库中看到了这个问题。 UNIQUES 和 INDEXES 对 INSERTS 有影响,许多文章都支持,如 The number of indexes on a table is the most dominant factor for insert performance
-
慢速插入的主要因素是没有有效地利用磁盘 I/O 和带宽。索引是使用 I/O 的一个子集,但它不是主要因素。这些类型的查询通过将几个插入查询包装到一个事务中进行优化,然后将它们刷新到磁盘而不是逐个执行。