《PHP精粹:编写高效PHP代码》——2.7节设计数据库

2.7 设计数据库
到目前为止,我们已经创建了两个非常基本的表并且看到如何使用PDO操作简单的数据。现在我们要扩展这些例子,添加一些另外的表,探讨我们如何在真实的应用程序中使用这些数据。让我们从图2.2开始,看看目前有什么。
图2.2显示了两张表以一对多的关系链接。这表明categories表中的每一个记录在食谱表中会有很多与之相关的记录;也就是说,一个类别会有很多食谱,但一个食谱只能属于一个类别。

2.7.1 主键与索引
我们已经为两张表添加了主键,主键使我们提供的列在每个表中必定是唯一的,我们可以轻松访问一个特定的记录。此外还有一个好处,MySQL可以在该列放置一个索引(index)。添加一个索引至数据库的列和要求数据库保持对其中内容的跟踪一样。例如,如果你在recipes.name列上添加了一个索引,数据库使用该列会很容易找到项目,因为索引会保持对这些记录在什么地方进行跟踪。

2.7.2 MySQL解析
我们应该学习的最后一个数据库方法是MySQL EXPLAIN命令。EXPLAIN详细描述了MySQL将如何运行查询。在SELECT查询之前,我们通过迅速放置EXPLAIN术语来使用它:

这表明我们的查询不得不搜索所有的5个行,以便找到正在寻找的一行。五行并不是很多,但在这种情况下它们就是表中的每一行,并且总是带来坏消息!如果我们经常用食谱名查询食谱表中的行,我们可以添加一个索引来提高性能。
如果要添加一个索引,需使用ALTER TABLE语句。因此,要在recipes.name列添加一个索引,我们将输入:

这表明如果我们试图在recipes表中插入一个id为4的记录,我们将看到一个错误消息。
外键支持
请注意并非所有的数据库都支持外键。MySQL支持外键,但只支持InnoDB表类型。使用MyISAM表类型,你可以创建一个外键,但是它会被忽略!在phpMyAdmin中,当你创建一个表,你会发现一个标题为Storage Engine的下拉菜单,你可以通过其中的选项来选择一个InnoDB表类型。

这是一个内部连接(inner join)的例子,这表明在这个查询中我们只能看到所有表中有匹配行的数据。我们在recipes表中还有其他的条目,但是因为我们仍需将一些配料和它们连接,所以这些条目不会在这个查询结果中出现。为了看到所有的食谱,无论它们有没有和配料连接,我们都将使用一个外部连接。
加入=内部连接
有时我们会看到只对自己使用JOIN关键字的查询,这些都是隐含的内部连接。这个例子使用了INNER关键字,让我们更清楚地看到发生了什么。我们很快将看到其他连接类型。

2.7.4 外部连接
现在你知道什么是内部连接了,你大概也猜到了什么是外部连接(outer join)。外部连接使我们能从一个表中检索所有行,还有其他表中与之匹配的行。如果没有匹配的数据,MySQL将对这些列返回NULL值。
由于外部连接包含的行来自于一个表及另一个随机的表,因此我们需要指定哪个表连接哪个表。我们使用RIGHT JOIN和LEFT JOIN表达式做到以上这些。因为我们是从左到右读,所以左边的表就是我们在SQL语句中遇到的第一个表。外部连接通常有助于勾勒出此时数据库的布局,或者你可以参考前面的架构图。
让我们来看看外部连接的一个例子。我们要显示所有的食谱,而不仅仅是带有配料的食谱。由于recipes表首先出现,因此我们将使用LEFT JOIN来表明需要显示左表中的所有行。

要是愿意,我们可以从包含在查询中的任一表格提取很多列或几列。若在多个表中有相同名称的列,我们必须为这些列加上它们所属表名的前缀,否则MySQL会告诉我们它不知道所指的是哪一列。这是一个修饰所有列名的好办法,可以帮助明确数据来源。当你想要添加另一个表到你的查询中时,这可让你免于返回去重新修饰这些列名。

2.7.5 聚合函数和Group By
聚合函数(aggregate function)向我们提供了与查询相匹配的简要数据信息。我们用这种技术能达到各种理想的结果。这种精确的功能不同于平台到平台模式,这里有一些常见的例子以及它们的MySQL函数名:
对记录计数(COUNT)。
得到最大或最小的一个特定列的值(MAX或MIN)。
计算某一列的总和(SUM)。
计算某一列的平均值(AVG)。
例如,若想知道在查询中有多少条记录,可以使用MySQL中的COUNT()函数,就像这样:

使用连接和聚合这两个函数的确非常棘手,但如果我们走一步看一步,对这些技术还是会慢慢理清头绪的。比起写一个庞大的SQL语句然后调试它,分阶段建立这些东西显然更加容易。
第一步是从一个表中得到数据并按照需要进行过滤。一次加入一个到表中,每次运行查询的时候,检查结果是否如你预期。一旦你看到MySQL根据请求算出的所有数据行,你就可以添加额外的格式化列、计算总数,以及其他任何需要为你应用程序生成的正确数据。使用聚合函数远比在PHP中为汇总数据集或计算平均数使用循环效率更高;数据库平台的确擅长处理数据,因此最好是把这些任务交给专家完成。

2.7.6 规格化数据
数据规格化的主题通常本身就可以构成一整章,但是,简而言之,使用这个方法的目标是:
按实体来拆分它们,并将拆分后的部分各自组成自己的表。
避免在一个列中有多个值。
在一个地方记录数据,并将其与其他数据连接。
按照现在的情况我们可以改善数据库设计,将chef列的数据移到一个单独的表中。每个厨师都有一个唯一的标识符,并且记录在recipes表中。由于厨师是一个实体,他应该有自己的表,在这里我们可以集中记录厨师的信息并且维护这些信息,而不是在每个recipe行中重复记录。
显而易见,如果允许用户输入名字会导致食谱表中出现很多个“John”,也许只有几个“John”,其中一些名字可能就是同一个人!为了避免发生这种情况,我们需要移动厨师到他们自己的表中,就像下面这样:

将数据分离进入表之后,我们给“厨师”这个实体建立了他们自己的表,这样可以避免在recipes表中重复记录值。这使我们更加接近最佳的标准化形式,并且巧妙地储存数据,允许我们使用本章前面读过的JOIN技术检索它们。

时间: 2024-09-18 05:19:51

《PHP精粹:编写高效PHP代码》——2.7节设计数据库的相关文章

《PHP精粹:编写高效PHP代码》——第2章数据库

第 2 章 数 据 库 数据库和数据存储是任何动态Web应用程序的关键组成部分,掌握何时使用数据库对我们非常重要,特别是如何使用PDO(PHP Data Object, PHP数据对象)扩展连接到一个数据库.接下来要讨论的PDO扩展示例使用MySQL,这可能是当今最流行的用于连接数据库的结构化查询语言.无论项目包含什么类型的数据库,都可用同样的方式在很多数据库平台使用PDO. 我们还将研究一些有益于数据库设计的技巧,这样可以最大限度地发挥应用程序的效率和性能.

《PHP精粹:编写高效PHP代码》——2.8节数据库—排序

2.8 数据库-排序 在本章,我们全面讲述了与PHP开发者息息相关的数据库主题.了解了PDO扩展并利用它在你的应用程序中建立稳定高效的代码. 除PHP外,我们还研究了一连串的数据库技术,这些技术以不同的方式在表中建立SQL查询.我们还使用索引,设计了经受住时间和可扩展性考验的数据库架构.

《PHP精粹:编写高效PHP代码》——3.3节数据格式

3.3 数据格式 在许多方面,Web服务仅仅只是一个网页,它提供机器可读的内容,而不是人类可读的内容.我们与其在一个浏览器的HTML网页标记标签,不如返回内容到JSON或XML中(我们马上将论及上述内容). 健壮性Web服务的强大特征之一便是它的设计可使其以不同的格式返回信息.因此,如果一个服务消费者更喜欢另一种数据格式,它可以轻易请求到最好的格式.这表明,当我们创建的服务公开后,解释请求和构成响应的方式是独立于代码中其他部分的. 接下来的两节将详细讲解JSON和XML,并举例说明如何以这种方式

《PHP精粹:编写高效PHP代码》——1.8节更多神奇的方法

1.8 更多神奇的方法 本章已介绍了一些神奇方法.在表1.1中快速回顾一下这些方法. 当在一个类中定义这些函数时,可以定义当这些事件发生时会引发什么.没有这些函数的话,类将显现为默认行为,而这些常常都是需要的.PHP另外还有一些神奇方法,在本节中我们将看到一些使用最频繁的方法. 1.8.1 使用__call()和__callStatic()方法 在关于访问修饰符的内容里,我们看到,对于__get()和__set()方法而言,__call()方法是一个天生的搭档.使用__get()和__set()

《PHP精粹:编写高效PHP代码》——3.4节HTTP:超文本传输协议

3.4 HTTP:超文本传输协议HTTP(HyperText Transfer Protocol)是通过导线来传送Web请求和响应的数据传输格式.它包含了很多请求和响应的元数据,除了这些请求或响应的实体之外,我们也可以利用它来使用Web服务.我们也将看到其他的协议,例如XML-RPC和SOAP,它们也都是建立在HTTP基础上的.当我们在本章快结尾构建RESTful服务时,便可以广泛使用HTTP的功能了.当我们开发一个简单的Web应用程序时,可能不会那么重视HTTP.但是如果你想了解缓存.不同文件

学习PHP精粹,编写高效PHP代码之质量保证

一.使用静态分析工具测量质量   我们用静态分析测量代码而不运行它.实际上,我们将这些工具用于评估代码.读取文件.衡量它所写的要素.使用这些工具,可以帮助我们对代码库有一个完整的层次化的认识,甚至在代码库变得更大.更复杂的时候也能掌握.   静态分析工具是项目过程中的一个关键组成部分,但是,只有定期使用它们,并以理想的方式进行每一次提交,静态分析工具才真正显示出价值.这些工具涵盖了代码的所有方面,从计数类和计算行数,到识别哪里有提示使用复制和粘贴的类似代码段.然后我们来看看静态分析工具在代码质量

《PHP精粹:编写高效PHP代码》——1.7节异常

1.7 异常 异常(exception)是一个处理错误的面向对象方法.一些PHP扩展像往常一样仍会报错:很多最新的扩展(例如PDO)将代替抛出异常.异常也是对象,而且Exception是PHP的一个内置类.一个Exception对象将包含发生错误的位置(文件名或代码行).一条错误消息和(可选)一个错误代码等信息. 1.7.1 处理异常 首先我们看看如何处理可能会抛出异常的函数.我们会使用一个PDO示例,因为PDO扩展抛出异常.在这里代码会试图创建一个数据库连接,但是会失败,因为nonsense主

《PHP精粹:编写高效PHP代码》——2.4节PHP数据库对象

2.4 PHP数据库对象 如果之前你使用过PHP和MySQL,你可能用过mysql或mysqli类库连接到数据库,如使用mysql_connect()函数.多年来,这是连接到MySQL数据库的标准方式,并且对于其他数据库平台也使用同样的方式. 这些类库可以直接使用,并形成了无数PHP应用程序类库和框架的基础.这种方式的缺点是每个扩展都与其他稍有不同,因此使得代码在数据库平台之间轻松转移变得复杂.虽然这些数据库特定类库依然活跃并且运转良好,但是本章中仍将专注讲解更先进的PDO扩展.创建的PDO扩展

《PHP精粹:编写高效PHP代码》——2.6节处理PDO中的错误

2.5 处理PDO中的错误 当你刚开始使用PDO时,它的某个方面是令人惊讶或让人沮丧的(视你的态度而定),即当它出现问题时,并不总是显而易见的.当我们第一次连接到数据库时,就会看到一个失败的连接会导致抛出一个异常.这里有一个提醒的代码: 一般来说,当某些引人注目的事情发生时PDO会抛出异常,但是如果你的查询由于某些原因而未能运行时,你也不必为此大惊小怪.这表明我们要仔细检查一切是否按照我们所预期的那样运行. 让我们复习一下迄今为止所学到的相关内容,看看我们如何对出现的问题进行识别和反应. 2.5

《PHP精粹:编写高效PHP代码》——2.6节高级PDO特征

2.6 高级PDO特征 我们已经看到PDO功能构成了以数据库驱动的PHP应用程序的主体.然而, PDO还有几个锦囊妙计需要我们好好研究.下面两节将显示我们如何利用数据库的事务,以及如何在PHP代码中调用存储过程. 2.6.1 事务和PDO 在数据库术语中事务(transaction)是一组必须执行的语句的集合.这组语句要么必须全部顺利完成,要么一个也不运行.不是所有的数据库都支持事务,有些支持,有些不支持,有些经过配置以后才会支持.对于MySQL,有些表的类型难以获得事务支持. 如果数据库不支持