【问题标题】:Reusing database query results (Perl)重用数据库查询结果 (Perl)
【发布时间】:2012-10-05 22:09:36
【问题描述】:

我正在使用 Perl 来填充两个 html 表(每个表都是在其自己的 Perl CGI 脚本中生成的)。我有一个运行 SQL 查询的“助手”脚本。这是一个例子(我们称这个脚本为run_sql_query.pl):

my $sql_query = "SELECT ID from TABLE where ID > 3";
our $sth = $dbh->prepare($sql_query);
$sth->execute;

然后,在我的两个 Perl CGI 脚本中,我都会这样做:

require 'run_sql_query.pl';

our $sth;
while (my ($table_id) = $sth->fetchrow_array) {
...
}

但是,run_sql_query.pl 似乎运行了两次(在每个 Perl CGI 脚本中运行一次)。我怎样才能让run_sql_query.pl 只执行一次,然后在两个 Perl CGI 脚本中使用相同的 $sth 内容?

【问题讨论】:

  • 你如何调用两个脚本来填充两个表?他们是iframes 吗?你在做某种 Ajax 调用吗?
  • 为确保我们理解,您有两个独立的 CGI 程序,例如 foo.cgibar.cgi。它们分别运行(即在不同的网络点击中)。他们每个人require 'run_sql_query.pl'。您希望他们共享数据吗?
  • @Schwern 是正确的。我想运行一次run_sql_query.pl 并在两个单独的 CGI 程序中使用该数据。
  • 好的,另一个问题。这是什么网络服务器?还有什么样的协议?快速CGI? mod_perl?纯CGI?阿贾克斯?
  • @Schwern 目前只使用普通 CGI。

标签: perl cgi dbi


【解决方案1】:

您应该在第一次遍历记录集时将查询结果输入哈希或数据结构中,然后再通过或引用哈希/结构:

my $dataStruct;

while (my ($table_id) = $sth->fetchrow_array) { 
     my $colVal = $sth->data[...];
     $dataStruct->{$table_id}->{'col'} = $colVal;
} 

然后你会遍历 $dataStruct。如果您需要说明如何操作,请告诉我。

【讨论】:

  • 如果我有两个单独的脚本,这会起作用吗?我可以在另一个脚本中引用在一个脚本中创建的哈希/结构吗?
  • 是的,如果调用 SQL 并将数据存储在内存中的脚本被定义为对象并且实例由其他脚本保持活动状态
【解决方案2】:

如果我理解正确,您希望保存查询结果,以便其他进程可以再次使用它。有几种方法可以做到这一点,都涉及设置某种缓存。

CGI 进程有单独的内存,所以你不能直接做你要求的事情。更糟糕的是,它们会为每个请求启动和停止,从而浪费大量时间进行编译。但是,有很多方法可以解决这个问题。

如果您的 SQL 查询开销很大,并且数据不经常更改,您可以让数据库缓存结果。例如,这是MySQL cache。这样做的好处是所有使用数据库的东西都将使用它。缺点是您的程序仍然必须获取和处理所有数据。使用它是您的查询很昂贵,但获取和处理它不是,而且您的数据不会经常更改。

另一种选择是设置一个外部缓存,例如memcached,来存储结果。 Memcached 基本上是您计算机上的一个服务器,用于存储大量数据。或者您甚至可以使用数据库本身来缓存处理后的 HTML 表。每个进程可以在自己计算之前检查他们想要的数据是否在缓存中。您可以使用CHI 之类的东西与之交互。优点是您可以将任何您想要的东西放入缓存中。缺点是你必须自己管理缓存(即数据用完时删除数据),这是另外一回事,而且缓存随时可能消失。

最后,您可以更改流程的运行方式。一个基本的效率提升是从简单的 CGI 改变,它为每个请求启动、编译、运行和完成你的程序,到像 FastCGI 这样在它自己的小服务器上运行你的程序。可以把它想象成在整个程序周围放置一个while 循环。现在,由于您的程序不会在每个请求之间关闭,您可以将数据存储在全局变量中。然后按照@foampile 的建议做一件简单的事情,将您的表格存储在our @Table_Cache 或类似的地方。这将为该进程缓存它,但不为其他进程缓存。每个不同的程序都是它自己的进程。所以foo.cgi 不会与bar.cgi 共享。优点是它很简单,无论如何你都应该切换到 FastCGI,而且你的 Web 服务器可能已经支持它。缺点是需要管理缓存(即删除过期的条目),而且不跨进程共享。

我会从 FastCGI 开始,看看是否能解决您的性能问题。这意味着您将在每次服务器重启时只运行每个查询两次,而不是在每次请求时运行。

【讨论】:

  • 您错过了最明显的数据存储位置:在数据库中。
  • @ikegami OP 已经在这样做并且存在性能问题(尽管我怀疑它们确实源于使用普通 CGI 而不是更好的东西)。还是您的意思是使用数据库作为后处理结果的外部缓存?
  • 是的,这并不是真正的性能问题,而是效率问题。我来看看 FastCGI。
【解决方案3】:

没有办法在进程(甚至线程)之间真正共享 Perl 变量。

但即使可以,整个概念也毫无意义。数据库无法知道它正在与两个客户端对话,因此一个客户端会以一些记录结束,而另一个会以其他一些记录结束我们。

您必须获取数据两次。您可以将数据存储在某个中间位置并让两个客户端从那里获取数据,但您没有表示有任何需要。

【讨论】:

    猜你喜欢
    • 2012-02-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-21
    • 2013-02-19
    相关资源
    最近更新 更多