【问题标题】:Perl and SQLite - request to improve/optimize the multiple SQL INSERT queriesPerl 和 SQLite - 请求改进/优化多个 SQL INSERT 查询
【发布时间】:2018-04-21 04:14:09
【问题描述】:

我在 JSON 文件中有大量数据,需要将其转换为 SQLite 数据库。我用 INSERT 查询做了一个简单的循环,但是查询需要很多时间。我是一个业余爱好者,我一直在学习。我觉得一定有更专业的解决方案。

use JSON::XS;
use DBI;

my $CCC = 'string';

# start connection to SQLite
my $dbh = DBI->connect(          
"dbi:SQLite:dbname=aaaa.db", "", "", { RaiseError => 1 }, ) or die $DBI::errstr;

my $stmt = "CREATE TABLE IF NOT EXISTS $CCC (id INTEGER PRIMARY KEY AUTOINCREMENT, start INTEGER UNIQUE, open REAL NOT NULL, high REAL NOT NULL, low REAL NOT NULL, close REAL NOT NULL, vwp REAL NOT NULL, volume REAL NOT NULL, trades INTEGER NOT NULL)";
my $sth = $dbh->prepare( $stmt );
my $rv = $sth->execute() or die $DBI::errstr;

if($rv < 0) {
  print $DBI::errstr;
}

# Open file.json
open(my $fh, '<', file.json) or die "cannot open file";
{
  local $/;
  $data = <$fh>;
}

# Converting JSON format to Perl's variables
my $coder = JSON::XS->new->ascii->pretty->allow_nonref;
my $json = $coder->decode ($data);

# Loop. Im inserting every hash ({}) from file.json by INSERT sql statement
foreach (@{$json}) {
  my $stmt = "INSERT OR IGNORE INTO $CCC values (null, strftime('%s',\'$_->{T}\'), $_->{O}, $_->{H}, $_->{L}, $_->{C}, ".(($_->{H}+$_->{L}+$_->{C}+$_->{O}) / 4).", $_->{V}, 1)";
  my $sth = $dbh->prepare( $stmt );
  my $rv = $sth->execute() or die $DBI::errstr;

  if($rv < 0) {
    print $DBI::errstr;
  }
}

文件.json

[{"O": 1.0, "H": 1.0, "L": 0.00014, "C": 0.000145, "V": 176703.92394752, "T": "2018-02-16T00:00:00", "BV": 25.71390226}, {"O": 0.00014499, "H": 0.00014499, "L": 0.00011101, "C": 0.00012599, "V": 247646.2068748, "T": "2018-02-16T00:05:00", "BV": 30.66246148}, {"O": 0.00012599, "H": 0.0001295, "L": 0.000122, "C": 0.00012699, "V": 102563.86201627, "T": "2018-02-16T00:10:00", "BV": 12.88322597}]

你知道更有效的方法吗?

【问题讨论】:

  • 人们过去曾尝试过这种事情,例如stackoverflow.com/questions/1711631/…
  • 我有一个答案here 解决了这个问题。
  • 有效!来自 autocommit = 0 的查询在一分钟后结束,而其他两次尝试(没有此参数)运行了 30 分钟并且仍未完成。出于好奇,我会等待其他想法。您的循环和我的循环之间的性能是否应该存在差异?
  • @J.Doe:执行PRAGMA journal_mode = MEMORY 应该会产生重大影响。

标签: sql sqlite perl


【解决方案1】:

我认为您应该在 foreach 循环外准备语句和准备(使用占位符),然后在循环内执行。准备通常只需要进行一次。

foreach (@{$json}) {
  my $stmt = "INSERT OR IGNORE INTO $CCC values (null, strftime('%s',\'$_->{T}\'), $_->{O}, $_->{H}, $_->{L}, $_->{C}, ".(($_->{H}+$_->{L}+$_->{C}+$_->{O}) / 4).", $_->{V}, 1)";
  my $sth = $dbh->prepare( $stmt );
  my $rv = $sth->execute() or die $DBI::errstr;

  if($rv < 0) {
    print $DBI::errstr;
  }
}

也许是这样的:

my $stmt = "INSERT INTO $CCC values (?, ?, ?, ?, ?, ?, ?, ?, ?)";
my $sth = $dbh->prepare( $stmt );

foreach (@{$json}) {
    $sth->execute(undef, $_->{T}, $_->{O}, $_->{H}, $_->{L}, $_->{C}, ($_->{H}+$_->{L}+$_->{C}+$_->{O}) / 4, $_->{V}, 1) or die $DBI::errstr;
}

更新:按照Kjetil S.的建议将undef作为第一个参数

【讨论】:

  • execute 中,您可能应该将'null' 替换为undef(不带引号)。
猜你喜欢
  • 2020-06-03
  • 1970-01-01
  • 1970-01-01
  • 2021-07-18
  • 2011-05-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多