这里
,我们对数据库进行一次查询
,以获得所有的行
。代码不复杂,并且它将数据库作为其原有的用途使用
。 问题5:n+1模式
我真不知有多少次看到过这样的大型应用程序,其中的代码首先检索一些实体(比如说客户),然后来回地一个一个地检索它们,以得到每个实体的详细信息。我们将其称为n+1模式,因为查询要执行这么多次——一次查询检索所有实体的列表,然后对于n个实体中的每一个执行一次查询。当n=10时这还不成其为问题,但是当n=100或n=1000时呢?然后肯定会出现低效率问题。清单14展示了这种模式的一个例子。
DROPTABLEIFEXISTSauthors;
CREATETABLEauthors(
idMEDIUMINTNOTNULLAUTO_INCREMENT,
nameTEXTNOTNULL,
PRIMARYKEY(id)
);
DROPTABLEIFEXISTSbooks;
CREATETABLEbooks(
idMEDIUMINTNOTNULLAUTO_INCREMENT,
author_idMEDIUMINTNOTNULL,
nameTEXTNOTNULL,
PRIMARYKEY(id)
);
INSERTINTOauthorsVALUES(null,'JackHerrington');
INSERTINTOauthorsVALUES(null,'DaveThomas');
INSERTINTObooksVALUES(null,1,'CodeGenerationinAction');
INSERTINTObooksVALUES(null,1,'PodcastingHacks');
INSERTINTObooksVALUES(null,1,'
PHPHacks');
INSERTINTObooksVALUES(null,2,'PragmaticProgrammer');
INSERTINTObooksVALUES(null,2,'RubyonRails');
INSERTINTObooksVALUES(null,2,'ProgrammingRuby');
清单14.Schema.sql
该模式是可靠的,其中没有任何错误。问题在于访问数据库以找到一个给定作者的所有书籍的代码中,如下所示。
<?php
require_once('DB.php');
$dsn='
mysql://root:password@localhost/good_books';
$db=&DB::Connect($dsn,array());
if(PEAR::isError($db)){die($db->getMessage());}
functionget_author_id($name)
{
global$db;
$res=$db->query("SELECTidFROMauthorsWHEREname=?",
array($name));
$id=null;
while($res->fetchInto($row)){$id=$row[0];}
return$id;
}
functionget_books($id)
{
global$db;
$res=$db->query("SELECTidFROMbooksWHEREauthor_id=?",
array($id));
$ids=array();
while($res->fetchInto($row)){$ids[]=$row[0];}
return$ids;
}
functionget_book($id)
{
global$db;
$res=$db->query("SELECT*FROMbooksWHEREid=?",array($id));
while($res->fetchInto($row)){return$row;}
returnnull;
}
$author_id=get_author_id('JackHerrington');
$books=get_books($author_id);
foreach($booksas$book_id){
$book=get_book($book_id);
var_dump($book);
}
?>
清单15.Get.php
如果您看看下面的代码,您可能会想,“嘿,这才是真正的清楚明了。”首先,得到作者id,然后得到书籍列表,然后得到有关每本书的信息。的确,它很清楚明了,但是其高效吗?回答是否定的。看看只是检索JackHerrington的书籍时要执行多少次查询。一次获得id,另一次获得书籍列表,然后每本书执行一次查询。三本书要执行五次查询!
解决方案是用一个函数来执行大量的查询,如下所示。
<?php
require_once('DB.php');
$dsn='
mysql://root:password@localhost/good_books';
$db=&DB::Connect($dsn,array());
if(PEAR::isError($db)){die($db->getMessage());}
functionget_books($name)
{
global$db;
$res=$db->query(
"SELECTbooks.*FROMauthors,booksWHERE
books.author_id=authors.idANDauthors.name=?",
array($name));
$rows=array();
while($res->fetchInto($row)){$rows[]=$row;}
return$rows;
}
$books=get_books('JackHerrington');
var_dump($books);
?>
清单16.Get_good.php