2

我有以下最终将成为网页的 perl 代码:

my($dbh) = DBI->connect("DBI:mysql:host=dbsrv;database=database","my_sqlu","my_sqlp") or die "Canny Connect";
my($sql) = "SELECT * FROM hardware where srv_name = \"$srv_name\"";
my($sth) = $dbh->prepare($sql);
$sth->execute();

$sth->bind_col( 1, \my($db_id));
$sth->bind_col( 2, \my($db_srv_name));
$sth->bind_col( 5, \my($db_site));
$sth->fetchrow();
$sth->finish ();
my($sql) = "SELECT sites.\`site_code\`, sites.\`long_name\` FROM \`hardware\` JOIN \`sites\` ON \`sites\`.id=\`hardware\`.\`site\` where \`hardware\`.\`id\`=\'$db_id\'";
my($sth) = $dbh->prepare($sql);
$sth->execute();
$sth->bind_col( 1, \my($db_site_code));
$sth->bind_col( 2, \my($db_long_name));
$sth->fetchrow();
$sth->finish ();
$dbh->disconnect;
print "$db_site_code<br>$db_long_name";

上面的查询确实有效,但是我想知道的是有什么方法可以运行一个 SQL 查询并从站点数据库中获取 db_site_code 和 db_long_name 而无需运行第二个查询?硬件数据库在站点数据库中有外键“id”。

当您阅读有关关系数据库的任何内容时,他们都说这是迄今为止从数据库中获取数据的最有效方法,但我看不出这比仅运行 2 个选择查询要快得多。我上面所做的肯定会比"select from hardware where srv_name = $srv_name"那时更长"select from sites where id = db_site_id"吗?任何意见都非常感谢。

4

2 回答 2

0

除了@tadman 建议使用占位符之外,我也会将此标记为 sql 问题,但您的解决方案是简单地添加

srv_name = \"$srv_name\"

到您的第二个 where 子句,以便您的陈述是:

"SELECT sites.\`site_code\`, sites.\`long_name\` FROM \`hardware\` JOIN \`sites\` ON \`sites\`.id=\`hardware\`.\`site\` where \`hardware\`.\`id\`=\'$db_id\'";

不过,我强烈支持@tadman 的建议——尽可能使用准备好的语句和/或占位符。

于 2012-11-06T21:42:22.463 回答
0

这是一个如何使用占位符以及组合查询执行此操作的示例。如果我正确理解您的数据库,您可以省略第一个查询并在第二个查询中添加服务器名称而不是 ID。我可能在那里弄​​错了,但我的例子对于 Perl 的建议仍然很有价值。

use strict;
use warnings;
use DBI;

# Create DB connection
my $dbh = DBI->connect("DBI:mysql:host=dbsrv;database=database","my_sqlu","my_sqlp")
  or die "Cannot connect to database";
# Create the statement handle
my $sth = $dbh->prepare(<<'SQLQUERY') or die $dbh->errstr;
  SELECT s.site_code, s.long_name 
  FROM hardware h 
  JOIN sites s ON s.id=h.site 
  WHERE h.srv_name=?
SQLQUERY
$sth->execute('Server Name'); # There's the parameter
my $res = $sth->fetchrow_hashref; # $res now has a hash ref with the first row

print "$res->{'site_code'}<br>$res->{'long_name'}";

我想向您指出您的代码存在一些问题:

  • 你应该总是 use strictuse warnings. 他们让你的生活更轻松!
  • 您可以离开括号()使用my. 节省您的击键并使您的代码更具可读性。
  • 您可以(但不必,这是首选!)在没有参数的方法调用之后省略括号。自己决定。
  • 正如已经指出的,在 DBI中始终使用占位符。它们非常简单。现在你不必"用反斜杠转义了。相反,只需使用?.
  • 组合查询后,您可以将其放入 heredoc ( <<'SQLQUERY') 中。它是一个从下一行持续到分隔符 ( SQLQUERY) 的字符串。这样,您的查询就更易于阅读。
  • 您可以使用其中一种 ref-fetchrow方法将结果的所有列放入一个哈希中。我用过$sth->fetchrow_hashref是因为我觉得它最方便。您已经获得了完整的行,并且所有列都被命名为哈希键。
  • 如果在小范围内调用(如 short sub),则不需要finish语句句柄。一旦超出范围,它将由 Perl 自动完成并销毁。

关于性能的另一件事:如果只是偶尔运行,请不要担心。您可以使用DBI::Profile来分析您的查询,以查看哪种方式更快,但只有在确实需要时才应该这样做。

根据我的经验,特别是对于非常庞大的查询和非常繁忙的数据库,两三个查询比一个大查询要好得多,因为它们不会占用服务器资源。但同样,这是您需要分析和基准测试的内容(如果需要)。

于 2012-11-06T22:50:02.850 回答