如何使用Perl基于id更新具有不同值的每个DB记录?

时间:2016-05-20 11:11:44

标签: mysql perl dbi

我有一个哈希,其中包含所有计算用户'考试成绩(系统用户是我的学生),其中user_id是哈希的关键,等级是相应的值。这个哈希有超过50,000个元素。我想用这些计算的等级更新数据库。

首次尝试

my %grade_of = compute_grades_hash( ... );   # Some logic to compute grades
my $dbh = DBI->connect( ... ) or die( ... ); # DBI parameters are hidden in this sample
my $sql = "UPDATE User SET grade = ? WHERE id = ?";
my $sth = $dbh->prepare($sql);
foreach my $user_id ( keys %grade_of ) {
    $sth->execute( $grade_of{$user_id}, $user_id );
}

但是,如果我是对的,这会导致执行超过50,000个查询,这意味着超过50,000次访问数据库(如果我假设错误,请在此声明中随意纠正我。)

所以我写了第二次尝试

my %grade_of = compute_grades_hash( ... );   # Some logic to compute grades
my $dbh = DBI->connect( ... ) or die( ... ); # DBI parameters are hidden in this sample
my $sql = build_query ( \%grade_of );
my $sth = $dbh->prepare($sql);
$sth->execute();

sub build_query {
    # Builds a string in the followig form:
    #     UPDATE User
    #     SET grade = (case when user_id = 10 then 96
    #                       when user_id = 14 then 92
    #                       when user_id = 26 then 85
    #                       ... 
    #                  end)
    # So it generates a very long query-string for the 50000 records

    ...
    return $sql_query;
}

以下是我的问题:

  1. 这是该案件的正确解决方案吗?

  2. 很长的SQL语句会影响查询性能吗?

  3. Perl DBI和/或MySQL中的查询长度是否有任何限制?

  4. 还有更优雅的解决方案吗?我错过了内置功能 我可以使用它吗?

  5. 顺便说一下,如果答案取决于以下信息,以下是我的完整性系统规范:

    $ mysql --version 
    mysql  Ver 14.14 Distrib 5.6.25, for Linux (x86_64)
    
    $ perldoc -m DBI | grep -m1 VERSION 
    $VERSION = "1.621";
    
    $ perl --version 
    This is perl 5, version 18, subversion 2 (v5.18.2) built for x86_64-linux
    

2 个答案:

答案 0 :(得分:5)

您是否尝试过运行其中任何一种?

你的第一次尝试是正确的。这就是为数据库制作的那种东西。你的第二个版本可能要慢得多。根据SQL引擎的优化方式,但无论您如何制定SQL,您的数据库仍然必须进行50,000次更新。你的第二次尝试迫使它做更多的工作来决定那些更新是什么

您可以使用交易

来加快流程,并避免某些记录更新而其他记录无法更新的可能性

在开始更新数据库之前,请致电

$dbh->begin_work

当它们全部完成时,你需要

$dbh->commit

这将创建一个对表进行更改的列表,并在调用commit方法时 make 这些更改

无论如何,您应该使用测试数据库,因此我建议您设置一个包含可管理数量的数据,以便快速提供结果。然后你可以尝试你的两个选项,以及你想到的任何选项,并确定他们的行为方式

答案 1 :(得分:1)

这可能会更快:

CREATE TEMPORARY TABLE `Updates` (
           `user_id` ... NOT NULL,
           `grade`   ... NOT NULL
       );

INSERT INTO `Updates` VALUES
       ( ..., ... ),
       ( ..., ... ),
       ...;

ALTER TABLE `Updates` ADD UNIQUE `user_id`;

UPDATE `User`
  JOIN `Updates`
    ON `User`.`user_id` = `Updates`.`user_id`
   SET `User`.`grade` = `Updates`.`grade`;