什么是公共数据库开发的应用程序开发人员所犯的错误?

2008-09-20 15:00:47
问题评论:

近乎重复的stackoverflow.com/questions/346659/...

回答:

1.不使用适当的索引

这是一个相对容易,但仍发生所有的时间。外键应该上有索引。如果使用的在WHERE一个字段 (可能) 应在其上有索引。这种索引通常应包括根据需要执行的查询的多个列。

2.不强制实施参照完整性

这里您的数据库可能会发生变化,但如果数据库支持参照完整性 — 意味着保证所有外键指向实体的存在--应使用它。

它是经常可以看到这种失败的 MySQL 数据库。我并不认为 MyISAM 支持它。没有 InnoDB。您会发现 MyISAM 或那些正在使用 InnoDB 但不用仍使用的人员。

更多的下面︰

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

自然键是基于外部有意义的数据 (表面上) 唯一的键。常见示例包括产品号、 两个字母的州代码 (美国)、 社会安全号码等。代理项或技术的主键是指那些绝对没有在该系统之外的意义。它们发明了纯粹用于标识实体,并且通常自动递增字段 (SQL Server,MySQL,其他人) 或序列 (尤其是 Oracle)。

在我看来,您应该始终使用代理键。此问题已经在这些问题中提出:

这是某种程度上具有争议性的主题将不会在其获取通用的协议。虽然您可以找到一些人,认为自然键是在某些情况下确定,他们不会找到代理键除了可以说不需要任何批评。我觉得这就是很小的负面影响。

请记住,即使国家可以停止存在(例如,南斯拉夫)。

4.编写查询需要DISTINCT工作

您经常看到这在 ORM 生成查询。查看日志输出从休眠,您将看到所有查询开始︰

SELECT DISTINCT ...

这是一些快捷方式确保不返回重复的行,并因此得到重复的对象。有时,您会看到人也将这样做。如果您看到它过于很真实的红色标记。并不是DISTINCT已损坏或没有有效的应用程序。(上两个计数) 但它不是一个代理项或应急编写正确的查询。

我为什么讨厌互异:

其中,事情开始转在我看来可以是当开发人员构建大量查询,将表连接起来,并且突然之间他认识到,它看起来像他正在重复 (或更大) 行和他直接的响应此"问题,"他的"解决方案"是引发不同的关键字和之后所有他的问题会消失。

5.通过联接 favouring 聚合

由数据库应用程序开发的另一个常见的错误就是意识不到多少便宜的聚合 (即GROUP BY子句) 可以比作联接。

以使您了解这是范围有多大,我已经编写有关该主题几次这里,已为其大量的 downvoted。例如︰

SQL 语句的"加入"vs"分组依据和具有":

第一个查询︰

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

没错。我建议是联接版本聚合版本比快 20 倍。

6.不简化复杂查询视图

不是所有的数据库供应商支持的视图,但对于这样做的那些,他们可以极大地简化查询如果谨慎使用。例如,在一个项目上我使用普通方模型CRM。这是一种非常强大而且灵活的建模技术,但可能会导致许多联接。在此模型中出现︰

  • ︰ 人员和组织;
  • 当事方角色︰ 事物各方一样,例如,雇员和雇主;
  • 当事方角色的关系︰ 这些角色如何彼此相关。

示例︰

  • Ted 是一个人,正子类型的当事方;
  • Ted 具有多个角色,其中之一是雇员;
  • 英特尔是组织结构、 能力的子类型的当事方;
  • 英特尔有许多角色,其中之一是雇主;
  • 英特尔采用了 Ted,意味着其各自的角色之间没有关系。

因此没有加入链接到他的雇主的 Ted 的五个表。您承担所有员工都 (而不是企业) 的人员,并提供此帮助视图︰

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,但如果您不知道自己要做什么是真的非常容易创建网站容易受到攻击。没有总结它优于小胡继表的故事.

通过窗体数据和 cookie应始终被视为敌意和净化的 Url 的用户所提供的数据。请确保您将获得您的期望。

8.不使用预准备的语句

预准备的语句时编译减插入、 更新和WHERE子句中使用的数据的查询和提供的更高版本。例如︰

SELECT * FROM users WHERE username = 'bob'

vs

SELECT * FROM users WHERE username = ?

SELECT * FROM users WHERE username = :username

取决于您的平台。

我曾看到过这样进入他们屈膝的数据库。基本上,每次任何现代数据库遇到一个新的查询,它必须对其进行编译。如果遇到查询,出现之前,要让数据库缓存已编译的查询和执行计划的机会。通过执行查询了很多情形︰ 您在数据库能够找到解决办法,并相应地优化 (例如,通过在内存中锁定已编译的查询)。

使用预准备语句还提供有关某些查询正在使用频率有意义的统计信息。

预准备的语句也更好地保护您免受 SQL 注入攻击。

9.不规范化不够

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

只是本周我在其中有人有 imploded 数组并将其插入到数据库中的单个字段的某些代码运行。规范化的是子表 (即为一对多关系) 中单独的行被视为该数组的元素。

这还提出在用于存储用户 Id 的列表的最佳方法:

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

但缺乏规范化有多种形式。

更多︰

10.过度规范化

这似乎有悖于前一点但规范化,很多事情,像是一种工具。它是端和不端本身的一种手段。我认为许多开发人员忘记,开始将"方法"为"结束"。单元测试是明显的例子。

我曾对系统有了类似的客户端的巨大层次结构︰

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

这样,有可能获得任何有意义的数据之前大约 11 表连接在一起。有太多采取标准化的一个很好示例。

更是到点,进行认真的和考虑非规范化可以有极大的性能优势,但您无需执行此操作时非常小心。

更多︰

11.使用独占弧

弧形排斥是一个常见的错误具有两个或多个外键将创建一个表有并且只有一个可以为非空。大错误。首先变的更难维护数据的完整性。毕竟,即使有了参照完整性,不防碍两个或多个这些外键设置 (尽管存在复杂的检查约束)。

关系数据库设计的实用指南:

我们具有强烈建议对独占弧构造在可能的情况下,很好的理由,也可以是难于编写代码,从而带来更多的维护困难。

12.没有在所有执行查询的性能分析

实用主义暴烈极高,特别是在数据库世界。如果您要坚持原则,它们已经成为 dogma 则很可能做出错误的点到。需要从更高的聚合查询的示例。聚合版本可能看起来"很好",但其性能是 woeful。性能比较应该已经结束的辩论 (但并非) 但更多的点︰ spouting 这种不正确的视图就是未知的甚至是危险。

13.过度依赖于 UNION ALL 和特别联合构造

在 SQL 方面的联合只是串联顺着数据集时,即它们具有相同的类型和列数。二者之间的差异是 UNION ALL 是简单的串联,并应优先次序而联合将隐式地执行互异,若要删除重复的元组。

互异,类似的联合仍然占有一席之地。没有有效的应用程序。但是,如果您发现自己进行大量的特别是在子查询中,然后您可能做错误的事情。这可能是一种糟糕的查询构造或设计不佳数据模型强制您执行下列操作的情况。

联合,特别是当用于连接或相关子查询,可以阻断数据库。尽量避免他们只要有可能。

14.在查询中使用 OR 条件

这可能看起来无害。毕竟,插手均正常。或是否应确定太向右?不正确。基本上和条件来限制数据集而 OR 条件发展它但不是适合于优化的方法。特别是当不同的 OR 条件可能相交从而强制到优化程序有效地为使用不同的操作的结果。

坏︰

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

更好︰

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

现在您的 SQL 优化器可以有效地打开第一到第二个查询。但它不可能。只是不要理会。

15.不设计表单及其数据模型,以适用于高性能解决方案

这是一个硬点,以量化。它通常被观察其效果。如果您发现您自己编写相对简单的任务的麻烦查询或查询查找出相对简单的信息并不有效,然后在您可能有一个较差的数据模型。

在某些方面总结了此点,所有更早的但很多个执行某些操作,如查询优化通常首先完成时应进行谨慎的故事第二。首先应确保在尝试优化性能之前有良好的数据模型。Knuth 说过︰

过早的优化是万恶之根

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

一个特定进程的所有数据更改应该都是原子的。即如果操作成功,它是完全。如果失败,数据仍保持不变。-应该是半完成更改的任何可能性。

理想情况下,为了实现这一点的最简单方法是整个系统设计应努力支持通过单一的插入、 更新或删除语句的所有数据更改。在这种情况下,没有特殊的事务处理,需要为您的数据库引擎应自动这样做。

但是,如果任何进程都需要作为一个整体来保持一致的状态中的数据执行多个语句,则相应交易记录控制是有必要。

  • 开始之前的第一个语句的事务。
  • 提交事务后最后一条语句。
  • 任何错误,回滚事务。而且很 NB !别忘了要跳过/中止错误后执行的所有语句。

此外建议特别注意您的数据库连接层和数据库引擎进行交互的方式在这方面的 subtelties。

17.不了解设置基于范例

SQL 语言遵循一种特定模式,适用于特定种类的问题。尽管,各种特定于供应商扩展语言努力处理进行了 langues 在一些无关紧要的问题如 Java、 C#、 Delphi 等。

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

  • 不恰当地强加上数据库太多程序或命令性逻辑。
  • 不适当或过度使用游标。尤其是当一个查询就已经足够了。
  • 不正确地假定,触发每行在多行更新受影响的一次火灾。

确定明确划分责任范围,并尽量使用适当的工具来解决每个问题。

有关外键 MySQL 语句,没错,MyISAM 不支持框架,但您意味着只需使用 MyISAM 是不好的设计。曾用过一个原因 MyISAM 是 InnoDB 不支持全文本搜索,而且我不认为这是合理的。

在缺少一项重要信息,不使用事务。我见过太多的情况下,需要封装在一个事务的插入/更新的-唯一保持系统的出现严重破坏的是没有对这些记录的并发更新尚未。(或 noone 已经尚未注意到的损坏的数据)

这不应为 14 单独回答,因此它们可能 votedd 在有效地?

我认为这篇文章需要被正常化.

完全不同意 #3。是的国家可以停止存在,但国家/地区代码将继续表示同样的事情。同样的货币代码或美国各州。它是哑的在这些情况下使用代理键并创建查询中的开销必须包括一个额外的联接。我想说它是更安全的说,您可能应该做一个代理项用于特定于用户的数据 (因此,没有国家、 货币和美国各州)。

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

  • 自私的数据库设计和使用。开发人员通常将数据库视为其个人的永久对象存储而无需考虑数据中的其他利益相关者的需求。这也适用于应用程序架构师。差的数据库设计和数据完整性使硬供第三方使用的数据,并可以大大提高系统的生命周期成本。报告和 MIS 往往为在应用程序设计中能较差的表姐和仅事后完成。

  • 滥用 denormalised 的数据。尝试在应用程序中对其进行维护和 overdoing denormalised 的数据是数据完整性问题的食谱。尽量少用 denormalisation。不想要添加到查询中的联接不是 denormalising 的一个托辞。

  • 编写 SQL Scared。SQL 不是火箭科学,实际上相当很好地发挥作用。O/R 映射层都很擅长做简单而到该模型很好地拟合的查询中的 95%。有时 SQL 是完成工作的最好办法。

  • Dogmatic ' 否存储过程的策略。无论是否您认为存储的过程是邪恶,这种 dogmatic 的态度有什么地方软件项目。

  • 不了解数据库设计。标准化是您的朋友,它是没有特别复杂。加入和基数是非常简单的概念-如果您是数据库应用程序开发中涉及确实没有借口不了解它们。

我将在您如果我无法对此首先指出尤其是为您提供 1000 upvotes

有人可能会说,交易记录应在事务数据库和报告和 MIS 应该进行单独分析数据库中。因此获得这两个领域的最佳产品,并且每个人都快乐 (除了拥有编写数据转换脚本来生成后者不足前者差咖啡杯)。

不只是差的咖啡杯编写 ETL-使用质量较差数据框中几个关键的关系实际上没有记录在源,因为 MIS 应用中,系统中的数据的任何人的任何人都参与没完没了的对帐圆-fignts,能从较差的数据质量。

小的示例︰ 我有保险策略管理系统,需要加载到 ceded 再保险系统来计算潜在恢复 5 万索赔的状态。系统是较旧的客户端-服务器 COTS 包,甚至较旧的大型机系统的接口设计。两者都需要财务控制进行协调。此作业是完成每月一次的。您的逻辑将撰写一系列的用户情景定义要求并要求供应商向其现有产品中添加 web 服务包装报价。

然后您的 DBA 是迟钝或 incompetent。

  1. 不使用版本控制的数据库架构
  2. 使用直接对实时数据库
  3. 没有研究和了解更多高级数据库概念 (索引、 聚集的索引、 约束、 实例化的视图等)
  4. 无法测试可伸缩性...只有 3 或 4 行的测试数据将永远不会为您提供真正实时性能的真实图片

我的第二个,很大程度,#1 和 #2。对数据库进行更改的任何时候我转储架构及其版本;我有三个数据库安装程序,开发一个,转移一个,并实时一-任何曾经在实时数据库上获取"测试"!!

这里在红门我们采取步骤,以改善您的第一个点与 SQL 源代码管理 !谈话时我认为人们不会对数据库进行开发生产不再,但通常我研究从"紧急"修复所做的通常办法返回到开发环境中,这是另一个问题。

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

一些应用程序开发人员看到作为中间层/前结束代码直接扩展存储的过程。这似乎是 Microsoft 栈的开发人员,在一个常见特征 (我是其中一个,但我已经从它长大),并生成执行复杂的业务逻辑和工作流处理的多个存储的过程。效果好得多,这是完成在其他地方。

存储的过程是有用的它都有 actuallly 已经证明,真正的专业的一些因素,必须使用 (例如,性能和安全) 例如,保持"接近数据"的大型数据集的聚合/过滤。

我最近不得不帮助保持和增强大型 Delphi 桌面应用程序的业务逻辑的 70%,实现了规则 1400 SQL Server 存储过程 (在 UI 事件处理程序的其余部分)。这就是恶梦一场,主要原因在于引入有效的单元测试 TSQL,缺乏封装和较差的工具 (调试器编辑器) 的 difficuly。

在过去使用 Java 团队却迅速发现,通常完全相反持有在该环境中。Java 架构师曾经告诉我:"数据库是数据而不保留代码。"。

我认为它是一个错误,根本不考虑存储的过程,但应谨慎使用这些天 (而不是通过默认值) 的情况下,它们提供有用的好处 (请参见其他答案)。

存储的过程的影响在任何项目中使用的其中一个岛趋于因此某些开发人员创建规则"没有存储的过程"。因此,看起来像没有打开冲突 beteween 他们。您的答案将如何实际选择的一种方法,或另一个好的方案。

优点︰ 安全-您不必向应用程序提供的功能"删除 * 从...";调整的 DBA 的可以调整查询,而无需重新编译/部署整个应用程序;分析-可以很容易地以确保它们仍然有效,则为数据模型更改后重新编译多个过程最后,考虑 SQL 执行由数据库引擎 (未应用程序),然后只需 retarded"数据库是数据,而不是代码的"这一概念。

因此,将 enmesh 您在 UI 中,是与正在处理的数据的业务逻辑?这看来并不是这样一个不错的主意,特别是在数据操作是通过数据库服务器而不是从用户界面的往返过程执行时最有效。这也意味着它是更加难以控制应用程序,因为您不能依赖于要在控件中的数据的数据库,可能有不同版本的用户界面有不同的数据处理进展情况。不好。我不让任何东西接触我除了通过存储过程的数据。

如果有需要的用户界面与业务逻辑分离,则可以使用多层体系结构。或与业务对象及使用不同的应用程序 Ui 的逻辑存储库。存储的过程锁定您的数据/业务逻辑与特定数据库,将数据库更改这种情况下是非常昂贵。和巨大成本不正常。

@ 太︰ 更改在大多数情况下数据库是非常昂贵。Nevermind 失去了解的性能和安全性功能的思想提供了特定 DBMS。此外,其他层增加了复杂性和降低性能,其它图层与特定的语言。最后,很有可能被使用的语言会改变比数据库服务器。

第一问题吗?他们只测试玩具的数据库上。因此,它们有其 SQL 在数据库获取大,并要自如并修复它后面有人将爬网不知道 (它可以听到的声音是我牙摩擦)。

数据库的大小相关,但更大的问题是负载--即使您在真实数据集上测试在生产负载时,它可以是真实的 eye-opener 数据库时,您不会测试查询的性能。

我想说,数据库大小是高于负载大的问题。我见过很多时候,它存在缺少关键索引-永远不会在测试时,被性能问题,因为整个数据库装入内存

请输入您的翻译

Database development mistakes made by application developers [closed]

确认取消