不管我们喜欢与否,我们开发人员中的许多人(如果不是大多数的话)都经常使用数据库,或者有一天可能不得不使用数据库。考虑到大量的误用和滥用,以及每天出现的大量与数据库相关的问题,公平地说,有一些概念是开发人员应该知道的——即使他们今天不设计或使用数据库。
关于数据库,开发人员和其他软件专业人员应该知道的一个重要概念是什么?
每个开发人员都应该知道这是错误的:“分析数据库操作与分析代码完全不同。”
在传统意义上有一个明确的Big-O。当你执行EXPLAIN PLAN(或等效)时,你看到的是算法。一些算法涉及嵌套循环,是O(n ^ 2)。其他算法涉及b树查找,它们是O(n log n)。
EXPLAIN PLAN
这是非常非常严重的。这是理解为什么索引很重要的关键。这对于理解速度-标准化-非标准化之间的权衡至关重要。这对于理解为什么数据仓库使用星型模式是非常重要的,而星型模式并没有对事务更新进行规范化。
如果您不清楚所使用的算法,请执行以下操作。停止。解释查询执行计划。相应调整指标。
同样,结论是:索引越多越好。
有时,专注于一个操作的索引会降低其他操作的速度。根据这两个操作的比例,添加一个索引可能有良好的效果,也可能没有整体影响,或者对整体性能不利。
好问题。以下是一些想法,排名不分先后:
标准化,至少是第二种标准形式,是必不可少的。
引用完整性也很重要,需要考虑适当的级联删除和更新。
正确使用检查约束。让数据库做尽可能多的工作。
不要将业务逻辑分散在数据库和中间层代码中。选择其中之一,最好是在中间层代码中。
决定主键和聚集键的一致方法。
不要过度索引。明智地选择索引。
一致的表和列命名。选择一个标准并坚持下去。
限制数据库中接受空值的列数。
不要被触发器冲昏了头脑。他们有他们的用途,但会在短时间内使事情复杂化。
小心udf。它们很棒,但是当您不知道在查询中调用它们的频率时,可能会导致性能问题。
获取Celko关于数据库设计的书籍。这个人很傲慢,但很懂行。
我希望每个人,包括dba和开发人员/设计人员/架构师,都能更好地理解如何正确地对业务领域建模,以及如何将业务领域模型映射/转换为规范化的数据库逻辑模型、优化的物理模型和适当的面向对象类模型(每种模型由于各种原因(可能)不同),并理解何时、为什么以及它们(或应该)如何彼此不同。
我会说有很强的SQL基础技能。到目前为止,我见过许多对数据库了解不多的开发人员,但总是询问如何制定一个相当简单的查询的技巧。查询并不总是那么容易和简单。在查询规范化良好的数据库时,必须使用多个连接(内部连接、左连接等)。
对于一个经常使用数据库(每天或几乎每天编写/维护查询)的中间职业开发人员,我认为期望应该与任何其他领域相同:你在大学时写过。
每个c++极客在大学里都写过一个字符串类。每个图形狂人在大学里都写过一个光线追踪器。每个网络极客在大学里都写过交互式网站(通常在我们有“web框架”之前)。每个硬件书呆子(甚至软件书呆子)在大学里都做过CPU。大学里每个内科医生都解剖过一整具尸体,即使她今天只是给我量血压,告诉我胆固醇太高。为什么数据库会有所不同呢?
不幸的是,由于某种原因,他们今天看起来确实不一样了。人们希望。net程序员知道C语言中的字符串是如何工作的,但你的RDBMS的内部你不应该太担心。
仅仅通过阅读,甚至从上到下都不可能达到同样的理解水平。但是,如果您从底层开始并理解每个部分,那么就相对容易找出数据库的细节。甚至是许多数据库极客似乎无法理解的事情,比如何时使用非关系数据库。
也许这有点严格,特别是如果你在大学里没有学习计算机科学。我将把它调低一些:你今天就可以写,完全,从头开始。我不关心你是否知道PostgreSQL查询优化器的工作原理,但如果你知道足够多的知识自己编写一个,它可能不会与他们所做的有太大的不同。你知道,写一个基本的公式并不难。
非常好的问题。让我们看看,首先,没有完全理解连接的人不应该考虑查询数据库。这就像开车时不知道方向盘和刹车在哪里一样。您还需要了解数据类型以及如何选择最佳数据类型。
开发人员应该了解的另一件事是,在设计数据库时,你应该记住三件事:
数据完整性——如果不能依赖数据,那么实际上就没有数据——这意味着不要在应用程序中放入所需的逻辑,因为许多其他源可能会触及数据库。约束、外键和触发器是数据完整性所必需的。不要因为你不喜欢它们或不想花时间去理解它们而不使用它们。
性能——重构一个性能差的数据库是非常困难的,应该从一开始就考虑性能。执行相同的查询有许多方法,其中一些已知几乎总是更快,不学习和使用这些方法是短视的。在设计查询或数据库结构之前,阅读一些关于性能调优的书籍。
安全——这些数据是你公司的命脉,它也经常包含可能被盗的个人信息。学习如何保护数据免受SQL注入攻击、欺诈和身份盗窃。
在查询数据库时,很容易得到错误的答案。确保完全理解数据模型。请记住,实际决策通常是基于查询返回的数据做出的。当它是错误的,就会做出错误的商业决策。你可能会因为糟糕的询问而杀死一家公司,或者失去一个大客户。数据是有意义的,但开发者往往忘记了这一点。
数据几乎永远不会消失,考虑的是随着时间的推移存储数据,而不是今天如何获取数据。数据库在拥有10万条记录时运行良好,十年后可能就不那么好了。应用程序很少能像数据一样持久。这就是为什么性能设计如此重要的原因之一。
您的数据库可能需要应用程序不需要看到的字段。比如用于复制的guid,插入的日期字段。等。您还可能需要存储更改的历史,以及谁在什么时候做了更改,并能够从这个存储库中恢复坏的更改。在向网站询问如何修复忘记在更新中添加where子句并更新整个表的问题之前,请考虑一下您打算如何做到这一点。
永远不要在比生产版本更新的数据库版本中进行开发。永远、永远、永远不要直接针对生产数据库进行开发。
如果没有数据库管理员,请确保有人正在进行备份,并且知道如何恢复备份,并且已经测试过如何恢复备份。
数据库代码就是代码,没有理由不把它像其他代码一样放在源代码控制中。
首先,开发人员需要了解一些关于数据库的知识。它们不仅仅是输入SQL并得到结果集的神奇设备,而是具有自己的逻辑和癖好的非常复杂的软件。
其次,针对不同的目的有不同的数据库设置。如果有可用的数据仓库,则不希望开发人员从联机事务数据库生成历史报告。
第三,开发人员需要了解基本的SQL,包括连接。
除此之外,它还取决于开发人员参与的程度。我曾经工作过,我是开发人员,实际上是DBA, DBA只是在走道的另一边,而DBA则在各自的领域。(我不喜欢第三个。)假设开发人员参与了数据库设计:
他们需要了解基本的标准化,至少是前三种标准形式。除此之外,请找一个DBA。对于那些有过美国法庭(以及随便看的电视节目)经验的人来说,有一句便于记忆的话:“依靠钥匙,全部的钥匙,除了钥匙别无其他,帮你一把,科德。”
他们需要了解索引,我的意思是他们应该知道他们需要什么索引,以及它们可能如何影响性能。这意味着不要使用无用的索引,但不要害怕添加它们来辅助查询。任何进一步的工作(如余额)都应该留给DBA。
他们需要理解对数据完整性的需求,并能够指出他们在哪里验证数据,以及如果发现问题他们正在做什么。这并不一定要在数据库中(在数据库中很难向用户发出有意义的错误消息),但必须在某个地方。
他们应该具备如何制定计划的基本知识,以及如何大体阅读计划(至少足以判断算法是否有效)。
他们应该模糊地知道什么是触发器,什么是视图,以及可以对数据库进行分区。他们不需要任何细节,但他们需要知道如何向DBA询问这些事情。
他们当然应该知道不要干涉生产数据,或生产代码,或类似的东西,他们应该知道所有的源代码都进入VCS。
毫无疑问,我忘记了一些事情,但是一般的开发人员不需要是DBA,前提是手头有一个真正的DBA。
关于数据库,开发人员应该知道的第一件事是:数据库是用来干什么的?不是它们如何工作,也不是如何构建它们,甚至不是如何编写代码来检索或更新数据库中的数据。但是它们有什么用呢?
不幸的是,这个问题的答案是一个移动的目标。在数据库的鼎盛时期,20世纪70年代到90年代初,数据库是为了共享数据。如果你正在使用一个数据库,而你没有共享数据,你要么参与了一个学术项目,要么你在浪费资源,包括你自己。建立一个数据库和驯服一个DBMS是如此巨大的任务,就数据被多次利用而言,回报必须与投资相匹配。
为MySQL,或访问,或SQL Server构建数据库已经变得如此例行,以至于数据库几乎已经成为普通应用程序的例行部分。有时,最初有限的任务会随着任务的蔓延而不断提升,因为数据的真正价值变得显而易见。不幸的是,当数据库开始被推到企业范围内和任务关键的角色时,为单一目的而设计的数据库通常会严重失败。
关于数据库,开发人员需要了解的第二件事是整个数据中心视图世界。以数据为中心的世界观不同于以流程为中心的世界观,这是大多数开发人员所学过的最不同的观点。与这个差距相比,结构化编程和面向对象编程之间的差距相对较小。
开发人员需要学习的第三件事是数据建模,包括概念数据建模、逻辑数据建模和物理数据建模。
概念数据建模实际上是从以数据为中心的角度进行需求分析。
逻辑数据建模通常是对概念数据建模中发现的需求的特定数据模型的应用。关系模型的使用比任何其他特定模型都要多,开发人员肯定需要学习关系模型。为一个重要的需求设计一个强大且相关的关系模型并不是一项简单的任务。如果误解了关系模型,就无法构建良好的SQL表。
物理数据建模通常是特定于DBMS的,不需要学习太多细节,除非开发人员也是数据库构建者或DBA。开发人员需要了解的是,物理数据库设计可以在多大程度上与逻辑数据库设计分离,以及仅通过调整物理设计就可以在多大程度上生成高速数据库。
开发人员需要学习的下一件事是虽然速度(性能)很重要,但其他衡量设计优劣的指标更为重要,例如修改和扩展数据库范围的能力,或者编程的简便性。
最后,任何搅乱数据库的人都需要理解数据的价值往往比捕获数据的系统存在的时间更长. c。
唷!
关于以下对Walter M。的回答:
“写得很好!历史视角对于当时没有做数据库工作的人(比如我)来说非常有用。”
历史观点在某种意义上是绝对重要的。“忘记历史的人,注定要重蹈覆辙。”XML重复着过去的层次错误,图形数据库重复着过去的网络错误,OO系统迫使用户使用层次模型,而每个人即使只有十分之一的大脑都应该知道层次模型不适合真实世界的通用表示,等等,等等。
至于问题本身:
每个数据库开发人员都应该知道“关系型”不等于“SQL”。然后他们就会明白为什么他们会被DBMS供应商如此失望,为什么他们应该告诉同样的供应商想出更好的东西(例如真正的关系型DBMS),如果他们想继续从他们的客户那里为这些蹩脚的软件吸走大量的钱)。
每个数据库开发人员都应该了解关系代数的所有知识。这样,就不会再有开发者在Stack Overflow网站上发布“我不知道如何做我的工作,希望别人帮我做”这样的愚蠢问题了。
三件事是一个神奇的数字:
数据库也需要版本控制。
游标是slow,你可能不需要它们。
触发器是邪恶的*
*几乎总是
对于一些项目,面向对象模型更好。
对于其他项目,关系模型更好。
我总是很沮丧地看到有人努力编写一个过度复杂的查询,而这个查询用标准化的设计可以完全简单明了(“显示每个地区的总销售额。”)。
如果您在一开始就理解了这一点,并相应地进行设计,您将在以后为自己省去许多痛苦。在规范化之后,很容易对性能进行反规范化;要规范化一个从一开始就不是这样设计的数据库并不容易。
至少,您应该知道3NF是什么以及如何实现它。对于大多数事务性数据库,这是使查询易于编写和保持良好性能之间的一个很好的平衡。
当看到一个表或整个数据库没有索引,或者索引是任意的/无用的时,我总是感到震惊。即使你不是设计数据库,只是需要写一些查询,至少理解它仍然是至关重要的:
SELECT *
设计人员还应该注意常见的索引反模式,例如:
数据库索引的质量——以及你是否在编写查询时利用了它——是到目前为止性能中最重要的部分。在SO和其他论坛上发布的抱怨性能不佳的问题中,10个问题中有9个总是被证明是由于索引不好或表达式不sargable。
除了他们使用的语法和概念选项(例如连接、触发器和存储过程)之外,对于每个使用数据库的开发人员来说,有一件事是至关重要的:
了解您的引擎将如何执行您正在编写的查询。
我认为这很重要的原因仅仅是生产的稳定性。您应该知道您的代码是如何执行的,这样您就不会在等待一个长函数完成时停止线程中的所有执行,那么为什么您不想知道您的查询将如何影响数据库、程序甚至服务器呢?
这实际上是我的R&D团队遇到的比缺少分号或类似情况更多的问题。假设查询将快速执行,因为它在他们的开发系统上执行,表中只有几千行。即使生产数据库的大小相同,它也很可能会被更多地使用,因此会受到其他限制,比如多个用户同时访问它,或者其他地方的另一个查询出现错误,从而延迟该查询的结果。
即使是像连接如何影响查询性能这样简单的事情,在生产中也是非常宝贵的。许多数据库引擎的许多特性在概念上让事情变得更简单,但如果没有考虑清楚,可能会在性能上带来问题。
了解数据库引擎的执行过程,并为之制定计划。
我只是想指出一个观察结果——似乎大多数的回答都假设数据库与关系数据库是可以互换的。还有对象数据库,平面文件数据库。评估当前软件项目的需求是很重要的。从程序员的角度来看,数据库决策可以推迟到以后。另一方面,数据建模可以在早期实现,并带来很大的成功。
我认为数据建模是一个关键组件,是一个相对较老的概念,但它已经被软件行业中的许多人遗忘了。数据建模,尤其是概念建模,可以揭示系统的功能行为,并可作为开发的路线图。
另一方面,所需的数据库类型可以根据许多不同的因素来确定,包括环境、用户数量和可用的本地硬件(如硬盘空间)。
进化数据库设计。http://martinfowler.com/articles/evodb.html
这些敏捷方法使数据库更改过程易于管理、可预测和可测试。
开发人员应该知道,在版本控制、持续集成和自动化测试方面重构生产数据库需要什么。
进化数据库设计过程具有管理方面的问题,例如,在此代码库的所有数据库中,某个列在某个生命周期后将被删除。
分类和过程描述也使得为这些重构实现工具成为可能。
我想这里已经介绍了很多技术细节,我不想再补充了。我想说的一件事是,社交比技术更重要,作为应用程序开发人员,不要陷入“DBA知道最好的”的陷阱。
如果您在查询方面有性能问题,也要解决这个问题。自己进行研究,并要求dba解释发生了什么,以及他们的解决方案是如何解决问题的。
在你做了研究之后,也要提出你自己的建议。也就是说,我试图找到解决问题的合作解决方案,而不是将数据库问题留给dba。
避免SQL 注射和如何保护你的数据库
将反规范化视为可能的天使,而不是魔鬼,并将NoSQL数据库视为关系数据库的替代方案。
此外,我认为实体-关系模型是每个开发人员必须知道的,即使你不设计数据库。它将让您彻底理解数据库的所有内容。
我认为每个开发人员都应该理解数据库需要不同的范例。
在编写查询以获取数据时,需要一种基于集的方法。许多具有交互背景的人对此感到困惑。然而,当他们接受它时,他们可以获得更好的结果,即使解决方案可能不是第一次出现在他们以迭代为中心的思想中的解决方案。
阻抗失配问题,并了解常见缺陷或orm。
非唯一索引中的列顺序很重要。
第一列应该是其内容(即基数)变化最大的列。
这是为了帮助SQL Server在运行时如何使用索引创建有用的统计数据。
RDBMS兼容性
查看是否需要在多个RDBMS中运行应用程序。如有,可能需要:
否则,这些问题应该分开处理,并开发应用程序的不同版本(或配置)。
简单的尊重。
根据我使用关系数据库的经验,每个开发人员都应该知道:
—不同的数据类型:
为正确的工作使用正确的类型将使您的DB设计更健壮,查询更快,生活更轻松。
—了解1xM和MxM:
这是关系数据库的基本功能。您需要理解一对多和多对多关系,并在适当的时候应用它们。
——“< a href = " http://en.wikipedia.org/wiki/K.I.S.S " rel = " noreferrer " > K.I.S.S."原则同样适用于DB:
简单总是最好的。如果你已经学习了数据库是如何工作的,你将避免不必要的复杂性,这将导致维护和速度问题。
——指数:
光知道它们是什么是不够的。你需要知道什么时候使用,什么时候不使用。
另外:
不要依赖于SQL查询返回的行顺序。
了解用于数据库编程的工具!!
我浪费了很多时间试图理解为什么我的代码神秘地失败了。
例如,如果你正在使用。net,你需要知道如何正确使用System.Data.SqlClient命名空间中的对象。你需要知道如何管理你的SqlConnection对象,以确保它们被打开、关闭,并在必要时正确地处理。
System.Data.SqlClient
SqlConnection
你需要知道,当你使用SqlDataReader时,有必要将它与你的SqlConnection分开关闭。您需要了解如何在适当的时候保持连接打开,以及如何最小化对数据库的访问次数(因为它们在计算时间方面相对昂贵)。
SqlDataReader
永远不要以错误的文本编码插入数据。
一旦您的数据库受到多种编码的污染,您所能做的最好的事情就是应用启发式和手工劳动的某种组合。
这可能不是最重要的,但肯定是最被低估的话题。
索引的问题在于SQL教程通常根本不会提到它们,而且所有的玩具示例都可以在没有索引的情况下工作。
即使是更有经验的开发人员,也可以在不了解“索引使查询更快”索引的情况下写出相当好的(和复杂的)SQL。
这是因为SQL数据库使用干得好作为黑盒:
告诉我你需要什么(给我SQL),我来处理。
这可以很好地检索正确的结果。SQL的作者不需要知道系统在幕后做什么——直到一切变得非常缓慢.....
这时索引就成了一个话题。但这通常很晚了,而且某些人(一些公司?)已经遇到了真正的问题。
这就是为什么我我相信索引是在使用数据库时不能忘记的首要主题。不幸的是,它很容易忘记。
免责声明
参数是从我的免费电子书“使用索引,卢克”的前言中借来的。我花了很多时间来解释索引是如何工作的,以及如何正确地使用它们。