【问题标题】:Perl/MySQL Relationship QueryPerl/MySQL 关系查询
【发布时间】:2012-11-06 21:30:28
【问题描述】:

我有以下最终将成为网页的 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" 花费更长的时间?非常感谢任何 cmets。

【问题讨论】:

  • 在您对自己造成严重伤害之前,请花点时间在您的应用程序中使用proper SQL placeholders
  • 谢谢塔德曼。我会做。这仅适用于本地 Intranet,但我同意那里有一些邪恶的人,其中一些可能与我合作!
  • 您在内网上运行的代码随时可能成为您公开运行的代码。始终保持最佳安全习惯。
  • 此外,看起来最简单的用户通常会找到最奇怪的方法来获取他们通常不应该获取的数据,或者通过欺骗您的网络应用来创建“更高效”的快捷方式。
  • 如果您正确地转义所有数据,任何名为“O'Malley”的人都会非常感激。

标签: mysql sql perl relationship


【解决方案1】:

下面是一个如何使用占位符以及组合查询来执行此操作的示例。如果我正确理解您的数据库,您可以省略第一个查询并在第二个查询中添加服务器名称而不是 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。节省您的击键次数并使您的代码更具可读性。
  • 您可以(但不必,这是首选!)在没有参数的方法调用之后省略括号。自己决定。
  • 正如已经指出的,始终将placeholders 与 DBI 一起使用。它们非常简单。现在您不必使用反斜杠转义 "。相反,只需使用?
  • 组合查询后,您可以将其放入 heredoc (&lt;&lt;'SQLQUERY')。这是一个从下一行持续到分隔符 (SQLQUERY) 的字符串。这样一来,您的查询就更易于阅读。
  • 您可以使用 ref-fetchrow- 方法之一将结果的所有列放入一个哈希中。我使用了$sth-&gt;fetchrow_hashref,因为我觉得它最方便。你得到了完整的行,所有的列都被命名为哈希键。
  • 如果在小范围内调用(如简短的sub),则不需要finish 语句句柄。一旦超出范围,它将由 Perl 自动完成并销毁。

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

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

【讨论】:

  • 非常感谢辛巴克。非常好的建议,它给了我很多思考!你的例子正是我想要的。幸运的是,我刚刚创建了 Db,这是该项目的第一个 SQL,因此更改我的脚本/技术不需要太多努力。
  • @NuttyP 不客气。 =) 不要犹豫,提出更多问题,并始终显示代码!
【解决方案2】:

除了@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 的建议——尽可能使用准备好的语句和/或占位符。

【讨论】:

  • 所以我肯定和“从 id = $db_site 的站点中选择”而不是进行 JOIN 一样快吗?我还可以从硬件表中获得大约 30 个值,这些值没有包含在上面的代码中,但只需要来自站点表的 long_name 和 site_code。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-07-20
  • 2011-07-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多