应用程序开发人员所犯的数据库开发错误

应用程序开发人员常见的数据库开发错误有哪些?

126032 次浏览

忘记在表之间建立关系。我记得当我刚开始在我现在的雇主工作时,我不得不清理这些东西。

a)将查询值硬编码为字符串
b)将数据库查询代码放在Windows窗体应用程序的“OnButtonPress”动作中

两者我都见过。

1. 没有使用合适的索引

这是一个相对简单的问题,但它仍然经常发生。外键上应该有索引。如果你在WHERE中使用一个字段,你应该在它上面有一个索引。根据需要执行的查询,这样的索引通常应该涵盖多个列。

2. 没有强制引用完整性

您的数据库在这里可能有所不同,但如果您的数据库支持引用完整性(意味着所有外键都保证指向一个存在的实体),那么您应该使用它。

在MySQL数据库中,这种失败是很常见的。我不相信MyISAM支持它。InnoDB。你会发现有些人正在使用MyISAM,有些人正在使用InnoDB,但根本不用它。

更多:

3.使用自然主键而不是代理(技术)主键

自然键是基于(表面上)惟一的外部有意义的数据的键。常见的例子是产品代码、两个字母的州代码(美国)、社会保险号等等。代理键或技术主键是那些在系统之外完全没有意义的键。它们纯粹是为了识别实体而发明的,通常是自动递增的字段(SQL Server, MySQL,其他)或序列(最著名的是Oracle)。

在我看来,你应该总是使用代理键。这个问题出现在以下问题中:

这是一个有点争议的话题,你不会得到普遍的同意。虽然您可能会发现有些人认为自然键在某些情况下是可以的,但您不会发现任何对代理键的批评,除了可以说是不必要的之外。要我说,这是一个很小的缺点。

记住,即使是国家可能会不复存在(例如,南斯拉夫)。

4. 编写需要DISTINCT才能工作的查询

您经常在orm生成的查询中看到这一点。查看Hibernate的日志输出,您将看到所有查询都以以下开头:

SELECT DISTINCT ...

这是一种确保不会返回重复行从而获得重复对象的捷径。你有时也会看到有人这样做。如果你看到太多,那就是一个真正的危险信号。并不是说DISTINCT不好或没有有效的应用程序。它确实(在这两方面),但它不是编写正确查询的替代品或权宜之计。

从# EYZ0:

事情开始变坏在我的 意见是当一个开发者 建实体查询、加盟 桌子在一起,突然之间 他意识到他就是这样 获取重复的(甚至更多)行 他的直接反应…他的 “解决”这个“问题”的方法就是 抛出DISTINCT关键字和吹熄蜡烛的声音

.他所有的烦恼都消失了

5. 聚合优于连接

数据库应用程序开发人员的另一个常见错误是没有意识到与连接相比,聚合(即GROUP BY子句)的开销要高得多。

为了让你知道这个问题有多普遍,我在这里写过几次这个话题,并且因为它而被否决了很多次。例如:

从# EYZ0:

第一个查询:

SELECT userid
FROM userrole
WHERE roleid IN (1, 2, 3)
GROUP by userid
HAVING COUNT(1) = 3

查询时间:0.312 s

第二个查询:

SELECT t1.userid
FROM userrole t1
JOIN userrole t2 ON t1.userid = t2.userid AND t2.roleid = 2
JOIN userrole t3 ON t2.userid = t3.userid AND t3.roleid = 3
AND t1.roleid = 1

查询时间:0.016 s

< p >这是正确的。连接版本I 建议是快20倍 聚合版本。

6. 没有通过视图简化复杂的查询

并不是所有的数据库供应商都支持视图,但对于那些支持视图的供应商,如果使用得当,它们可以极大地简化查询。例如,在一个项目中,我使用一般政党模型来进行CRM。这是一种非常强大和灵活的建模技术,但可能导致许多连接。在这个模型中有:

  • 聚会,派对:个人和组织;
  • 政党的作用:双方所做的事情,例如雇员和雇主;
  • 政党角色关系:这些角色如何相互关联。

例子:

  • 泰德是一个人,是一个政党的子类型;
  • Ted有很多角色,其中一个是员工;
  • 英特尔是一个组织,是一个政党的子类型;
  • 英特尔有很多角色,其中之一是雇主;
  • 英特尔雇佣了泰德,这意味着他们各自的角色之间有关系。

有五张桌子连接在一起,把泰德和他的雇主联系起来。假设所有员工都是person(不是组织),并提供以下帮助视图:

CREATE VIEW vw_employee AS
SELECT p.title, p.given_names, p.surname, p.date_of_birth, p2.party_name employer_name
FROM person p
JOIN party py ON py.id = p.id
JOIN party_role child ON p.id = child.party_id
JOIN party_role_relationship prr ON child.id = prr.child_id AND prr.type = 'EMPLOYMENT'
JOIN party_role parent ON parent.id = prr.parent_id = parent.id
JOIN party p2 ON parent.party_id = p2.id

突然之间,你就有了一个非常简单的数据视图,但却有了一个高度灵活的数据模型。

7. 没有消毒输入

这是一个巨大的问题。现在我喜欢PHP,但如果你不知道你在做什么,它真的很容易创建易受攻击的网站。没有什么比小鲍比的故事更能概括它了。

用户通过url提供的数据,表单数据和饼干应该始终被视为敌对和消毒。确保你得到了你想要的。

8. 不使用准备好的语句

准备语句是指在编译查询时减去插入、更新和WHERE子句中使用的数据,然后再提供这些数据。例如:

SELECT * FROM users WHERE username = 'bob'

vs

SELECT * FROM users WHERE username = ?

SELECT * FROM users WHERE username = :username

这取决于你的平台。

我曾看到数据库因为这样做而崩溃。基本上,任何现代数据库每次遇到新的查询都必须编译它。如果它遇到了以前见过的查询,就给了数据库缓存已编译查询和执行计划的机会。通过大量执行查询,可以让数据库有机会发现并相应地进行优化(例如,将编译后的查询固定在内存中)。

使用准备语句还可以提供有关某些查询使用频率的有意义的统计数据。

准备好的语句还可以更好地保护您免受SQL注入攻击。

9. 不够正常化

数据库规范化基本上是优化数据库设计或如何将数据组织到表中的过程。

就在本周,我遇到了一些代码,其中有人将一个数组内爆,并将其插入到数据库中的一个字段中。规范化的方法是将该数组的元素视为子表中的单独行(即一对多关系)。

这也出现在存储用户id列表的最佳方法中:

我在其他系统中看到,列表存储在一个序列化的PHP数组中。

但是,缺乏正常化有多种形式。

更多:

10. 过度正常化

这似乎与前面的观点相矛盾,但是正常化,像许多事情一样,是一种工具。它是达到目的的一种手段,本身并不是目的。我认为许多开发者忘记了这一点,开始将“手段”视为“目的”。单元测试就是一个很好的例子。

我曾经工作过一个系统,它为客户端提供了一个巨大的层次结构,大概是这样的:

Licensee ->  Dealer Group -> Company -> Practice -> ...

因此,在获得任何有意义的数据之前,您必须将大约11个表连接在一起。这是正常化走得太远的一个很好的例子。

更重要的是,仔细考虑的非正规化可以带来巨大的性能好处,但在这样做时必须非常小心。

更多:

11. 使用独占弧

排他弧是一个常见的错误,其中一个表创建了两个或多个外键,其中一个且只有一个外键可以是非空的。首先,维护数据完整性变得更加困难。毕竟,即使使用引用完整性,也没有什么可以阻止设置两个或多个外键(尽管有复杂的检查约束)。

从# EYZ0:

我们强烈建议不要在任何地方建造排他性的弧形建筑 有可能,因为它们编写代码时会很尴尬

12. 根本没有对查询进行性能分析

实用主义是至高无上的,尤其是在数据库领域。如果你坚持的原则已经成为教条,那么你很可能已经犯了错误。以上面的聚合查询为例。综合版本可能看起来“不错”,但其性能却很糟糕。一场业绩比较本应结束这场争论(但它并没有),但更重要的是:从一开始就发表这种无知的观点是无知的,甚至是危险的。

13. 过度依赖UNION ALL,特别是UNION结构

在SQL术语中,UNION只是连接一致的数据集,这意味着它们具有相同的类型和列数。它们之间的区别是UNION ALL是一个简单的连接,应该在任何可能的地方被优先使用,而UNION将隐式地执行DISTINCT来删除重复的元组。

工会,像DISTINCT,有他们的位置。有有效的申请。但是如果您发现自己做了很多这样的事情,特别是在子查询中,那么您可能做错了什么。这可能是由于糟糕的查询结构或设计糟糕的数据模型迫使您这样做。

union,特别是在连接或依赖子查询中使用时,可能会削弱数据库。只要有可能就尽量避免。

14. 在查询中使用OR条件

这似乎是无害的。毕竟,and是可以的。OR应该也可以吧?错了。基本上,一个AND条件限制是数据集,而一个OR条件生长是数据集,但在某种程度上并不利于优化。特别是当不同的OR条件可能相交时,从而迫使优化器有效地对结果进行DISTINCT操作。

缺点:

... WHERE a = 2 OR a = 5 OR a = 11

好:

... WHERE a IN (2, 5, 11)

现在,SQL优化器可以有效地将第一个查询转换为第二个查询。但事实可能并非如此。千万别这么做。

15. 没有将数据模型设计为适合高性能解决方案

这一点很难量化。它通常是通过其效果来观察的。如果您发现自己为相对简单的任务编写了复杂的查询,或者用于查找相对直接的信息的查询效率不高,那么您可能有一个糟糕的数据模型。

在某种程度上,这一点总结了所有早期的观点,但它更像是一个警世故事,做像查询优化这样的事情,往往是在应该第二做的时候先做的。首先,在尝试优化性能之前,您应该确保拥有良好的数据模型。正如Knuth所说:

过早的优化是万恶之源

16. 数据库事务的不正确使用

特定流程的所有数据更改都应该是原子性的。也就是说,如果操作成功,则完全成功。如果失败,则数据保持不变。不应该出现“半途而废”的改动。

理想情况下,实现这一点的最简单方法是,整个系统设计应该努力通过单个INSERT/UPDATE/DELETE语句来支持所有数据更改。在这种情况下,不需要特殊的事务处理,因为数据库引擎应该自动处理。

但是,如果任何流程确实需要将多条语句作为一个单元执行,以保持数据处于一致状态,则需要适当的事务控制。

  • 在第一条语句之前开始一个事务。
  • 在最后一条语句之后提交事务。
  • 对于任何错误,回滚事务。非常NB!不要忘记跳过/中止错误之后的所有语句。

还建议仔细注意数据库连接层和数据库引擎在这方面如何交互的细微差别。

17. 不理解“基于集合”的范式

SQL语言遵循一种适用于特定类型问题的特定范式。尽管有各种特定于供应商的扩展,但该语言仍难以处理在Java、c#、Delphi等语言中微不足道的问题。

这种理解的缺乏体现在几个方面。

  • 不恰当地在数据库上强加了太多的过程逻辑或命令式逻辑。
  • 游标使用不当或过多。尤其是当一个问题就足够了。
  • 错误地假设在多行更新中每个受影响的行触发一次火灾。

确定明确的职责分工,力求用合适的工具解决每一个问题。

不使用索引。

  • 非常大的事务,插入/更新大量数据,然后重新加载它。基本上,这是因为没有考虑数据库工作的多用户环境。

  • 过度使用函数,特别是作为select和where子句中的结果,导致函数被反复调用以获取结果。我认为,这符合他们试图以他们更习惯的过程方式工作而不是充分利用SQL的一般情况。

没有做正确的归一化级别。您希望确保数据没有重复,并且根据需要将数据分割为不同的数据。您还需要确保您没有遵循规范化,因为这会损害性能。

使用Access而不是“真正的”数据库。有很多很棒的小型甚至免费的数据库,比如SQL ExpressMySQLSQLite,它们可以更好地工作和扩展。应用程序通常需要以意想不到的方式进行扩展。

在我的经验:
没有与有经验的dba沟通

. bat

. bat

当查询在您的开发机器上运行得如此之快时,一旦您向应用程序抛出一些流量,查询就会崩溃并阻塞,这要归咎于db引擎。

  1. 不对数据库模式使用版本控制
  2. 直接针对活动数据库工作
  3. 没有阅读和理解更高级的数据库概念(索引、聚集索引、约束、物化视图等)
  4. 没有测试可伸缩性……只有3或4行的测试数据永远不会给您真实的实时性能的真实画面

第一个问题?他们只在玩具数据库上测试。因此,他们不知道当数据库变大时,他们的SQL将会爬行,并且稍后必须有人来修复它(您可以听到的声音是我咬牙切齿的声音)。

过度使用和/或依赖存储过程。

一些应用程序开发人员将存储过程视为中间层/前端代码的直接扩展。这似乎是微软堆栈开发人员的一个共同特征(我是其中之一,但我已经不再这样做了),并产生许多执行复杂业务逻辑和工作流处理的存储过程。这在其他地方做得更好。

存储过程在某些实际技术因素(例如性能和安全性)需要使用时非常有用。例如,保持大型数据集的聚合/过滤“接近数据”。

我最近不得不帮助维护和增强一个大型Delphi桌面应用程序,其中70%的业务逻辑和规则是在1400个SQL Server存储过程中实现的(其余在UI事件处理程序中)。这是一场噩梦,主要是由于难以将有效的单元测试引入TSQL,缺乏封装和糟糕的工具(调试器,编辑器)。

在过去与Java团队一起工作时,我很快发现在那个环境中,情况往往完全相反。一位Java架构师曾经告诉我:“数据库是用于数据的,而不是用于代码的。”

现在,我认为完全不考虑存储过程是错误的,但在它们提供有用好处的情况下,应该谨慎使用(不是默认情况)(参见其他答案)。

将数据库仅仅视为一种存储机制(即美化的集合库),因此从属于它们的应用程序(忽略其他共享数据的应用程序)

不使用参数化查询。它们在停止SQL注入时非常方便。

这是一个不消毒输入数据的具体例子,在另一个回答中提到过。

这里有一个Scott Walz的视频“典型的数据库开发错误和五种克服它们的方法”的链接

开发人员所犯的关键数据库设计和编程错误

  • 自私的数据库设计和使用。开发人员通常将数据库视为他们个人的持久对象存储,而不考虑其他涉众对数据的需求。这也适用于应用程序架构师。糟糕的数据库设计和数据完整性使第三方很难使用数据,并会大大增加系统生命周期的成本。在应用程序设计中,报告和MIS往往是一个可怜的兄弟,只是事后才做的。

  • 滥用非规范化数据。过度使用非规范化数据并试图在应用程序中维护它会导致数据完整性问题。谨慎使用非规范化。不想向查询添加连接不是去规范化的借口。

  • 害怕写SQL。SQL不是火箭科学,实际上它很擅长做它的工作。O/R映射层非常擅长完成95%的简单查询,并很好地适合该模型。有时SQL是完成这项工作的最佳方式。

  • 教条的“无存储过程”策略。不管你是否认为存储过程是邪恶的,这种教条主义的态度在软件项目中是没有位置的。

  • 不了解数据库设计。正常化是你的朋友,它是不是火箭科学。连接和基数是相当简单的概念——如果你从事数据库应用程序开发,真的没有理由不理解它们。

在where子句中的值上不必要地使用函数,其结果是该索引未被使用。

例子:

where to_char(someDate,'YYYYMMDD') between :fromDate and :toDate

而不是

where someDate >= to_date(:fromDate,'YYYYMMDD') and someDate < to_date(:toDate,'YYYYMMDD')+1

在较小的程度上:不向需要函数索引的值添加函数索引……

没有添加检查约束以确保数据的有效性。查询优化器可以使用约束,它们确实有助于确保您可以信任您的不变量。没有理由不使用它们。

出于懒惰或时间压力,向表中添加未规范化的列。事情通常不是这样设计的,而是演变成这样的。最终的结果是,当您在未来的演进中受到丢失的数据完整性的困扰时,将会有大量的工作试图清理混乱。

想想看,重新设计一个没有数据的表是非常便宜的。一个有数百万条记录的表,没有完整性……重新设计并不便宜。因此,在创建列或表时执行正确的设计是可以分摊的。

4 -不是关于数据库本身,但确实很烦人。不关心SQL的代码质量。SQL是用文本表示的事实并不意味着可以将逻辑隐藏在大量的字符串操作算法中。完全有可能用文本编写SQL,使您的程序员同事能够读懂。

没有对应用程序中的数据库连接管理给予足够的重视。然后,您发现应用程序、计算机、服务器和网络都阻塞了。

  • 因为“它太神奇了”或“不在我的数据库上”等原因,立即放弃像Hibernate这样的ORM。
  • 过度依赖像Hibernate这样的ORM,并试图将它硬塞到不合适的地方。

我想补充: 偏好“优雅”代码而不是高性能代码。在应用程序开发人员看来,对数据库最有效的代码通常是丑陋的。< / p >

相信过早优化的废话。数据库必须在原始设计和后续开发中考虑性能。在我看来,性能是数据库设计的50%(40%是数据完整性,最后10%是安全性)。如果数据库不是为了执行而从下往上构建的,那么一旦将真实用户和真实流量放在数据库上,数据库的性能就会很差。过早的优化并不意味着没有优化!这并不意味着您应该编写几乎总是执行糟糕的代码,因为您发现它更容易(例如,游标永远不允许在生产数据库中,除非所有其他方法都失败了)。这意味着你不需要考虑挤出最后一点性能,直到你需要。很多人都知道什么在数据库上性能更好,在设计和开发中忽视这一点充其量是短视的。

前面已经说过了,但是:索引,索引,还是索引。我见过许多性能不佳的企业web应用程序,它们通过简单地进行一些分析(查看哪些表被频繁访问),然后在这些表上添加索引来解决问题。这甚至不需要太多的SQL编写知识,而且回报是巨大的。

像避免瘟疫一样避免数据复制。有些人主张,稍微复制一点不会有什么坏处,还会提高性能。嘿,我并不是说您必须将您的模式折磨成第三范式,直到它抽象到连DBA都不知道发生了什么。只要明白,无论何时复制一组名称、邮政编码或运输代码,副本最终都会彼此不同步。它会发生的。然后,在运行每周维护脚本时,您将会自我鞭策。

最后:使用清晰、一致、直观的命名约定。就像一段写得很好的代码应该是可读的一样,一个好的SQL模式或查询应该是可读的,并且实际上告诉你正在做什么,即使没有注释。六个月后,当你不得不对桌子进行维护时,你会感谢自己的。"SELECT account_number, billing_date FROM national_accounts"比“SELECT ACCNTNBR, BILLDAT FROM NTNLACCTS”更容易使用。

在运行DELETE查询之前没有执行相应的SELECT查询(特别是在生产数据库上)!

有一件事我想补充,学习使用分析函数,如分区BY, RANK, DENSE_RANK (Oracle)。它们对于复杂的查询是绝对必要的。

其他建议是,如果可能的话,在您的开发团队中有一个专门的数据库开发人员,他应该是SQL、数据库建模、调优等方面的专家(但不是DBA)。这种技能是一笔巨大的财富。

不了解数据库并发模型以及它如何影响开发。事后添加索引和调整查询很容易。然而,应用程序的设计没有适当考虑热点,资源争用 和正确的操作(假设你刚刚读到的仍然有效!)可能需要在数据库和应用层进行重大更改,以便稍后纠正

使用Excel存储(大量)数据。

我曾见过一些公司拥有数千行并使用多个工作表(由于以前版本的Excel的行数限制为65535)。


Excel非常适合用于报告、数据演示和其他任务,但不应被视为数据库。

对于基于sql的数据库:

  1. 没有利用聚集索引或选择错误的列进行群集。
  2. 在父/子表关系中,不使用SERIAL(自动编号)数据类型作为PRIMARY KEY连接到FOREIGN KEY (INT)。
  3. 当插入或删除了许多记录时,没有更新表上的统计信息。
  4. 当插入或删除许多行时,不重新组织(即卸载,删除,重新创建,加载和重新索引)表(一些引擎在表中使用delete标志物理地保留已删除的行)。
  5. 没有在具有高事务率的大表上利用FRAGMENT ON表达式(如果支持)。
  6. 为列选择错误的数据类型!
  7. 没有选择合适的列名。
  8. 不在表的末尾添加新列。
  9. 没有创建适当的索引来支持常用的查询。
  10. 在可能值很少的列上创建索引,并创建不必要的索引 ...还需要添加更多内容。李< / >

使用一些疯狂的构造和应用逻辑,而不是简单的COALESCE。

相关子查询导致的性能差

大多数情况下,您希望避免相关子查询。如果子查询中存在对外部查询的列的引用,则子查询是相关的。当发生这种情况时,对于返回的每一行至少执行一次子查询,如果在应用包含相关子查询的条件之后应用其他条件,则可以执行更多次。

请原谅这个不自然的示例和Oracle语法,但假设您想要找到自上次商店每天销售额低于10,000美元以来在任何商店中雇用的所有员工。

select e.first_name, e.last_name
from employee e
where e.start_date >
(select max(ds.transaction_date)
from daily_sales ds
where ds.store_id = e.store_id and
ds.total < 10000)

本例中的子查询通过store_id与外部查询相关联,并将对系统中的每个员工执行。优化此查询的一种方法是将子查询移动到内联视图。

select e.first_name, e.last_name
from employee e,
(select ds.store_id,
max(s.transaction_date) transaction_date
from daily_sales ds
where ds.total < 10000
group by s.store_id) dsx
where e.store_id = dsx.store_id and
e.start_date > dsx.transaction_date

在这个例子中,from子句中的查询现在是一个内联视图(同样是一些Oracle特定的语法),并且只执行一次。根据数据模型的不同,这个查询的执行速度可能会快得多。随着员工数量的增加,它将比第一个查询执行得更好。如果员工很少而商店很多(可能许多商店没有员工),并且daily_sales表是在store_id上建立索引的,那么第一个查询实际上会执行得更好。这不是一个可能出现的场景,但显示了相关查询如何可能比替代查询执行得更好。

我曾多次看到初级开发人员关联子查询,这通常会对性能产生严重影响。然而,当删除一个相关的子查询时,一定要查看解释计划之前和之后,以确保您没有使性能变差。

如果您正在使用复制(MySQL),以下函数是不安全的,除非您正在使用基于行的复制。

USER(), CURRENT_USER() (or CURRENT_USER), UUID(), VERSION(), LOAD_FILE(), and RAND()

看到:# EYZ0

# EYZ0

如果不了解离合器的工作原理,你就不能正确地驾驶变速杆。如果不了解实际上只是在硬盘上写入文件,就无法理解如何使用数据库。

具体地说:

  1. 你知道聚集索引是什么吗?你在设计图式的时候考虑过吗?

  2. 你知道如何正确使用索引吗?如何重用索引?你知道什么是覆盖指数吗?

  3. 很好,有索引。索引中的一行有多大?当你有很多数据时,索引会有多大?这能很容易地放进记忆里吗?如果不能,作为索引就没用了。

  4. 你用过MySQL中的EXPLAIN吗?太好了。现在诚实地对自己说:你所看到的,你能理解一半吗?不,你可能没有。解决这个问题。

  5. 您了解查询缓存吗?你知道什么使查询不可缓存吗?

  6. 你在用MyISAM吗?如果你需要全文搜索,MyISAM是垃圾。使用斯芬克斯。然后切换到Inno。

1)不了解如何正确地在Java和数据库之间进行交互。

2)过度解析,不恰当或没有重用SQL

3)没有使用BIND变量

4)在数据库中使用SQL集逻辑时,用Java实现过程逻辑(更好)。

5)在投入生产前没有进行任何合理的性能或可伸缩性测试

6)使用水晶报表,在报表中没有正确设置模式名

7)由于不了解执行计划,使用笛卡尔式产品实现SQL(你甚至看了EXPLAIN计划吗?)

  1. 使用ORM进行批量更新
  2. 选择多于需要的数据。同样,这通常在使用ORM时完成
  3. 在循环中触发sql。
  4. 没有良好的测试数据,只在实时数据上注意到性能下降。

好吧,我不得不说应用程序开发人员犯的最大错误是没有正确地规范化数据库。

作为一名应用程序开发人员,我意识到正确的数据库结构、规范化和维护的重要性;我花了无数的时间自学数据库结构和管理。根据我的经验,每当我开始与不同的开发人员合作时,我通常必须重新构造整个数据库并更新应用程序以适应,因为它通常是畸形的和有缺陷的。

例如,我开始了一个新项目,开发人员要求我在网站上实现Facebook Connect。我打开数据库,看看我必须处理什么,看到关于任何给定用户的每一点信息都被塞进了一个表。。我花了6个小时写了一个脚本,将表组织成4到5个独立的表,另外两个小时让应用程序使用这些表。请# EYZ1

  1. 认为他们是dba和数据建模师/设计人员,而他们在这些领域没有任何正式的灌输。

  2. 认为他们的项目不需要DBA,因为这些东西都很简单/琐碎。

  3. 未能正确区分应该在数据库中完成的工作和应该在应用程序中完成的工作。

  4. 未验证备份,或未备份。

  5. 在他们的代码中嵌入原始SQL。

我认为所有开发人员和dba所犯的最大错误就是过于相信约定。我的意思是,惯例只是在大多数情况下起作用的指导方针,但不一定总是如此。 我的一个很好的例子是归一化和外键,我知道大多数人不喜欢这样,但归一化也会导致复杂性和性能损失,所以如果没有理由移动一个电话号码到电话表,就不要这样做。对于外键,它们在大多数情况下都很好,但如果您试图创建一些可以在需要时自行工作的东西,那么外键将在将来成为一个问题,而且还会降低性能。 无论如何,正如我所说的规则和惯例是用来指导的,它们应该总是被考虑,但不一定要执行,对每个案例进行分析是应该做的
  • 在修复生产数据库内部的一些问题之前没有进行备份。

  • 在存储过程中的存储对象(如表、视图)上使用DDL命令。

  • 害怕使用存储的proc或害怕在更有效/更合适的地方使用ORM查询。

  • 忽略数据库分析器的使用,它可以准确地告诉您ORM查询最终转换为什么,从而验证逻辑,甚至在不使用ORM时进行调试。

二十年来我见过的最常见的错误是:没有提前计划。许多开发人员将创建数据库和表,然后在构建应用程序时不断修改和扩展表。最终的结果往往是一团糟,效率低下,之后很难清理或简化。

我讨厌开发人员使用嵌套的选择语句,甚至在查询的“select”部分中返回选择语句的结果的函数。

我很惊讶我在其他地方没有看到这个,也许我忽略了它,尽管@adam也有类似的问题。

例子:

SELECT
(SELECT TOP 1 SomeValue FROM SomeTable WHERE SomeDate = c.Date ORDER BY SomeValue desc) As FirstVal
,(SELECT OtherValue FROM SomeOtherTable WHERE SomeOtherCriteria = c.Criteria) As SecondVal
FROM
MyTable c

在这个场景中,如果MyTable返回10000行,结果就好像查询只运行了20001个查询,因为它必须运行初始查询,并对每一行结果查询一次其他表。

开发人员可以在只返回几行数据且子表通常只有少量数据的开发环境中使用这种查询,但在生产环境中,随着向表中添加更多数据,这种查询的成本可能会呈指数级增长。

一个更好的(不一定完美的)例子是这样的:

SELECT
s.SomeValue As FirstVal
,o.OtherValue As SecondVal
FROM
MyTable c
LEFT JOIN (
SELECT SomeDate, MAX(SomeValue) as SomeValue
FROM SomeTable
GROUP BY SomeDate
) s ON c.Date = s.SomeDate
LEFT JOIN SomeOtherTable o ON c.Criteria = o.SomeOtherCriteria

这允许数据库优化器将数据混合在一起,而不是从主表中重新查询每条记录,我通常发现,当我必须修复产生这个问题的代码时,我通常会将查询速度提高100%或更多,同时减少CPU和内存使用。

许多开发人员倾向于对数据库执行多个查询(通常查询一个或两个表),提取结果并在java/c/c++中执行简单的操作——所有这些都可以用一条SQL语句完成。

许多开发人员通常没有意识到,在开发环境中,数据库和应用程序服务器在他们的笔记本电脑上——但在生产环境中,数据库和应用程序服务器将在不同的机器上。因此,对于每个查询,在应用程序服务器和数据库服务器之间传递的数据都有额外的n/w开销。我惊奇地发现,为了向用户呈现一个页面,应用程序服务器对数据库服务器进行了大量的数据库调用!

最大的错误是在代码中使用循环更新或插入数据,而基于集合的简单解决方案可以更快、更简单地完成这一任务。