当前位置:中国站长下载文章中心网页编程PHP编程 → 五个常见 PHP 数据库问题

五个常见 PHP 数据库问题

减小字体 增大字体 作者:编辑整理  来源:互联网  发布时间:2008-9-15 22:04:18
ersVALUES(2,'jon','pass');
在这些文件的多数据库版本中,您应该将SQL语句加载到一个数据库中,然后将usersSQL语句加载到另一个数据库中。用于在数据库中查询与某个特定用户相关联的文件的PHP代码如下所示。

清单8.Getfiles.php

 <?php
require_once("DB.php");

functionget_user($name)
{
 $dsn='mysql://root:password@localhost/bad_multi1';
 $db=&DB::Connect($dsn,array());
 if(PEAR::isError($db)){die($db->getMessage());}

 $res=$db->query("SELECTidFROMusersWHERElogin=?",array($name));
 $uid=null;
 while($res->fetchInto($row)){$uid=$row[0];}

 return$uid;
}

functionget_files($name)
{
 $uid=get_user($name);

 $rows=array();

 $dsn='mysql://root:password@localhost/bad_multi2';
 $db=&DB::Connect($dsn,array());
 if(PEAR::isError($db)){die($db->getMessage());}

 $res=$db->query("SELECT*FROMfilesWHEREuser_id=?",array($uid));
 while($res->fetchInto($row)){$rows[]=$row;}
 return$rows;
}

$files=get_files('jack');

var_dump($files);
?>
get_user函数连接到包含用户表的数据库并检索给定用户的ID。get_files函数连接到文件表并检索与给定用户相关联的文件行。

做所有这些事情的一个更好办法是将数据加载到一个数据库中,然后执行查询,比如下面的查询。

清单9.Getfiles_good.php

 <?php
require_once("DB.php");

functionget_files($name)
{
 $rows=array();

 $dsn='mysql://root:password@localhost/good_multi';
 $db=&DB::Connect($dsn,array());
 if(PEAR::isError($db)){die($db->getMessage());}

 $res=$db->query("SELECTfiles.*FROMusers,filesWHERE
users.login=?ANDusers.id=files.user_id",
array($name));
 while($res->fetchInto($row)){$rows[]=$row;}

 return$rows;
}

$files=get_files('jack');

var_dump($files);
?>


该代码不仅更短,而且也更容易理解和高效。我们不是执行两个查询,而是执行一个查询。

尽管该问题听起来有些牵强,但是在实践中我们通常总结出所有的表应该在同一个数据库中,除非有非常迫不得已的理由。

问题4:不使用关系

关系数据库不同于编程语言,它们不具有数组类型。相反,它们使用表之间的关系来创建对象之间的一到多结构,这与数组具有相同的效果。我在应用程序中看到的一个问题是,工程师试图将数据库当作编程语言来使用,即通过使用具有逗号分隔的标识符的文本字符串来创建数组。请看下面的模式。

清单10.Bad.sql

 DROPTABLEIFEXISTSfiles;
CREATETABLEfiles(
 idMEDIUMINT,
 nameTEXT,
 pathTEXT
);

DROPTABLEIFEXISTSusers;
CREATETABLEusers(
 idMEDIUMINT,
 loginTEXT,
 passwordTEXT,
 filesTEXT
);

INSERTINTOfilesVALUES(1,'test1.jpg','media/test1.jpg');
INSERTINTOfilesVALUES(2,'test1.jpg','media/test1.jpg');
INSERTINTOusersVALUES(1,'jack','pass','1,2');
系统中的一个用户可以具有多个文件。在编程语言中,应该使用数组来表示与一个用户相关联的文件。在本例中,程序员选择创建一个files字段,其中包含一个由逗号分隔的文件id列表。要得到一个特定用户的所有文件的列表,程序员必须首先从用户表中读取行,然后解析文件的文本,并为每个文件运行一个单独的SELECT语句。该代码如下所示。

清单11.Get.php

 <?php
require_once("DB.php");

functionget_files($name)
{
 $dsn='mysql://root:password@localhost/bad_norel';
 $db=&DB::Connect($dsn,array());
 if(PEAR::isError($db)){die($db->getMessage());}

 $res=$db->query("SELECTfilesFROMusersWHERElogin=?",array($name));
 $files=null;
 while($res->fetchInto($row)){$files=$row[0];}

 $rows=array();

 foreach(split(',',$files)as$file)
 {
$res=$db->query("SELECT*FROMfilesWHEREid=?",
array($file));
while($res->fetchInto($row)){$rows[]=$row;}
 }

 return$rows;
}

$files=get_files('jack');

var_dump($files);
?>
该技术很慢,难以维护,且没有很好地利用数据库。惟一的解决方案是重新架构模式,以将其转换回到传统的关系形式,如下所示。

清单12.Good.sql

 DROPTABLEIFEXISTSfiles;
CREATETABLEfiles(
 idMEDIUMINT,
 user_idMEDIUMINT,
 nameTEXT,
 pathTEXT
);

DROPTABLEIFEXISTSusers;
CREATETABLEusers(
 idMEDIUMINT,
 loginTEXT,
 passwordTEXT
);

INSERTINTOusersVALUES(1,'jack','pass');
INSERTINTOfilesVALUES(1,1,'test1.jpg','media/test1.jpg');
INSERTINTOfilesVALUES(2,1,'test1.jpg','media/test1.jpg');
这里,每个文件都通过user_id函数与文件表中的用户相关。这可能与任何将多个文件看成数组的人的思想相反。当然,数组不引用其包含的对象——事实上,反之亦然。但是在关系数据库中,工作原理就是这样的,并且查询也因此要快速且简单得多。清单13展示了相应的PHP代码。

清单13.Get_good.php

 <?php
require_once("DB.php");

functionget_files($name)
{
 $dsn='mysql://root:password@localhost/good_rel';
 $db=&DB::Connect($dsn,array());
 if(PEAR::isError($db)){die($db->getMessage());}

 $rows=array();
 $res=$db->query("SELECTfiles.*FROMusers,filesWHEREusers.login=?
ANDusers.id=files.user_id",array($name));
 while($res->fetchInto($row)){$rows[]=$row;}
 return$rows;
}

$files=get_files('jack');

var_dump($files);
?>


这里,我们对数据库进行一次查询,以获得所有的行。代码不复杂,并且它将数据库作为其原有的用途使用。

问题5:n+1模式

我真不知有多少次看到过这样的大型应用程序,其中的代码首先检索一些实体(比如说客户),然后来回地一个一个地检索它们,以得到每个实体的详细信息。我们将其称为n+1模式,因为查询要执行这么多次——一次查询检索所有实体的列表,然后对于n个实体中的每一个执行一次查询。当n=10时这还不成其为问题,但是当n=100或n=1000时呢?然后肯定会出现低效率问题。清单14展示了这种模式的一个例子。

清单14.Schema.sql

 DROPTABLEIFEXISTSauthors;
CREATETABLEauthors(
 idMEDIUMINTNOTNULLAUTO_INCREMENT,
 nameTEXTNOTNULL,
 PRIMARYKEY(id)
);

DROPTABLEIFEXISTSbooks;
CREATETABLEboo

上一页  [1] [2] [3]  下一页