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

时间:2009-03-07 14:12:06

标签: database database-design

应用程序开发人员常见的数据库开发错误是什么?

40 个答案:

答案 0 :(得分:1003)

答案 1 :(得分:110)

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

  • 自私的数据库设计和使用。开发人员经常将数据库视为个人持久对象存储,而不考虑数据中其他利益相关者的需求。这也适用于应用程序架构师。糟糕的数据库设计和数据完整性使第三方难以处理数据,并且可能大大增加系统的生命周期成本。报告和MIS往往是应用程序设计中的一个表兄弟,只是事后才想做。

  • 滥用非规范化数据。过度使用非规范化数据并尝试在应用程序中维护它是数据完整性问题的一个方法。谨慎使用非规范化。不希望在查询中添加联接不是非规范化的借口。

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

  • Dogmatic'无存储程序'政策。无论您是否认为存储过程是邪恶的,这种教条态度在软件项目中都没有。

  • 不理解数据库设计。规范化是你的朋友,not rocket science.加入和基数是相当简单的概念 - 如果你参与数据库应用程序开发,那真的没有借口不理解他们。

答案 2 :(得分:80)

  1. 未在数据库架构上使用版本控制
  2. 直接针对实时数据库
  3. 不读取和理解更高级的数据库概念(索引,聚簇索引,约束,物化视图等)
  4. 未能测试可扩展性...只有3行或4行的测试数据永远不会给你真实的现场表现图片

答案 3 :(得分:46)

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

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

存储过程非常有用,因为它已被证实某些真正的技术因素需要使用它们(例如,性能和安全性)。例如,保持大数据集的聚合/过滤“接近数据”。

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

过去与Java团队合作我很快发现在这种环境中通常完全相反。 Java架构师曾告诉我:“数据库用于数据,而不是代码。”

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

答案 4 :(得分:41)

头号问题?他们只测试玩具数据库。所以当数据库变大时,他们不知道他们的SQL会爬行,而且有人必须在以后修复它(你可以听到的声音是我的牙齿磨损)。

答案 5 :(得分:31)

不使用索引。

答案 6 :(得分:28)

相关子查询导致性能不佳

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

原谅人为的例子和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上​​编入索引,那么第一个查询实际上可以更好地执行。这不是一种可能的情况,但显示了相关查询如何比替代查询更好地执行。

我见过初级开发人员多次关联子查询,而且通常会对性能产生严重影响。但是,在删除相关子查询时,请务必查看之前和之后的explain plan,以确保不会使性能变差。

答案 7 :(得分:21)

根据我的经验:
不与经验丰富的DBA沟通。

答案 8 :(得分:17)

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

答案 9 :(得分:16)

忘记设置表之间的关系。我记得当我第一次开始在现任雇主工作时必须清理它。

答案 10 :(得分:14)

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

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


Excel非常适合报表,数据展示和其他任务,但不应被视为数据库。

答案 11 :(得分:14)

我想补充一下: 在高性能代码上支持“优雅”代码。对应用程序开发人员来说,最适合数据库的代码通常很难看。

相信过早优化的废话。数据库必须考虑原始设计和任何后续开发中的性能。在我看来,性能是数据库设计的50%(40%是数据完整性,最后10%是安全性)。一旦真实用户和实际流量针对数据库放置,那么从下到上执行的数据库将执行不良。过早优化并不意味着没有优化!这并不意味着您应该编写几乎总是表现不佳的代码,因为您会发现它更容易(例如,除非所有其他方法都失败,否则永远不应该在生产数据库中使用游标)。这意味着在您需要之前,您不需要考虑挤出最后一点性能。关于什么在数据库上表现更好,众所周知,在设计和开发中忽略这一点至多是短视的。

答案 12 :(得分:13)

不使用参数化查询。他们在阻止SQL Injection时非常方便。

这是另一个答案中提到的不清理输入数据的具体示例。

答案 13 :(得分:12)

我讨厌当开发人员使用嵌套的select语句甚至函数时,在查询的“SELECT”部分内返回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和内存使用量。

答案 14 :(得分:12)

对于基于SQL的数据库:

  1. 没有利用CLUSTERED INDEXES或选择错误的列到CLUSTER。
  2. 不使用SERIAL(autonumber)数据类型作为PRIMARY KEY来加入父/子表关系中的FOREIGN KEY(INT)。
  3. 当许多记录被INSERTED或DELETED时,表上没有更新统计数据。
  4. 在插入或删除许多行时,不重组(即卸载,删除,重新创建,加载和重新编制索引)表(某些引擎在物理上将删除的行保留在带有删除标记的表中。)
  5. 在具有高交易率的大型表格上没有利用FRAGMENT ON EXPRESSION(如果支持)。
  6. 为列选择错误的数据类型!
  7. 未选择正确的列名。
  8. 不在表格的末尾添加新列。
  9. 未创建正确的索引以支持常用查询。
  10. 在具有少量可能值的列上创建索引并创建不必要的索引 ......还有更多要补充。

答案 15 :(得分:9)

  • 在修复生产数据库中的某些问题之前不进行备份。

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

  • 害怕使用存储过程或担心使用ORM查询,无论哪个更有效/适合使用。

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

答案 16 :(得分:8)

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

答案 17 :(得分:8)

1 - 不必在where子句中的值上使用函数,但该索引的结果未被使用。

示例:

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

而不是

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

在较小程度上:不向那些需要它们的值添加功能索引......

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

3 - 在纯懒惰或时间压力下向表中添加非标准化列。事情通常不是这样设计的,而是演变成这个。最终的结果是,当你在未来的演变中被丢失的数据完整性所困扰时,试图清理混乱的大量工作。

想想看,没有数据的表格重新设计非常便宜。一张表有几百万条没有完整性的记录......重新设计并不那么便宜。因此,在创建列或表时执行正确的设计将在黑桃中摊销。

4 - 与数据库本身无关,但确实很烦人。不关心SQL的代码质量。您的SQL以文本表达的事实并不能将逻辑隐藏在字符串操作算法的堆中。完全可以在文本中以一种实际可读的方式编写SQL。

答案 18 :(得分:8)

  • 由于“太神奇”或“不在我的数据库”等原因而无法解除像Hibernate这样的ORM。
  • 过分依赖像Hibernate这样的ORM,并试图在不合适的地方进行窃听。

答案 19 :(得分:8)

未执行normalization的正确级别。您希望确保数据不重复,并且您要根据需要将数据拆分为不同的数据。你还需要确保你没有遵循标准化,因为这会损害性能。

答案 20 :(得分:7)

之前已经说过,但是:索引,索引,索引。我已经看到很多表现不佳的企业网络应用程序,通过简单地进行一些分析(查看哪些表被击中很多),然后在这些表上添加索引来修复。这甚至不需要SQL编写知识的方式,而且收益很大。

避免像瘟疫一样的数据重复。有些人主张一点点重复不会伤害,并会提高性能。嘿,我不是说你必须将你的模式折磨成第三范式,直到它如此抽象,甚至连DBA都不知道发生了什么。只需理解,无论何时复制一组名称,邮政编码或运输代码,副本最终都会彼此不同步。它会发生。然后,当你运行每周维护脚本时,你会自己踢。

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

答案 21 :(得分:6)

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

答案 22 :(得分:5)

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

答案 23 :(得分:4)

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

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

  3. 无法正确识别应在数据库中完成的工作与应在应用中完成的工作。

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

  5. 在其代码中嵌入原始SQL。

答案 24 :(得分:4)

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

我已经看过了。

答案 25 :(得分:4)

没有足够重视管理应用程序中的数据库连接。然后你会发现应用程序,计算机,服务器和网络都被堵塞了。

答案 26 :(得分:3)

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

答案 27 :(得分:3)

不了解DBMS如何在幕后工作。

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

具体来说:

  1. 您知道聚集索引是什么吗?您在设计架构时是否考虑过它?

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

  3. 太好了,你有索引。索引中的1行有多大?当您拥有大量数据时索引有多大?这很容易融入记忆吗?如果它不会作为索引无用。

  4. 你曾经在MySQL中使用过EXPLAIN吗?大。现在对自己说实话:你有甚么了解你看到的一半吗?不,你可能没有。修复它。

  5. 您了解查询缓存吗?你知道是什么让查询无法访问吗?

  6. 您使用的是MyISAM吗?如果你需要全文搜索,MyISAM无论如何都是垃圾。使用Sphinx。然后切换到Inno。

答案 28 :(得分:3)

  1. 使用ORM进行批量更新
  2. 选择超出需要的数据。同样,通常在使用ORM
  3. 时完成
  4. 循环播放sqls。
  5. 没有良好的测试数据,只注意到实时数据的性能下降。

答案 29 :(得分:3)

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

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

例如,我开始使用一个新项目,开发人员要求我在网站上实施Facebook Connect。我破解了数据库以查看我必须使用的内容,并看到有关任何给定用户的每一点信息都被塞进一个表中。我花了六个小时编写一个可以组织的脚本将表分成四个或五个单独的表,另外两个表来让应用程序使用这些表。请规范化您的数据库!这将使其他一切不那么令人头痛。

答案 30 :(得分:3)

这是Scott Walz提供的名为“Classic Database Development Mistakes and five ways to overcome them”的视频链接

答案 31 :(得分:2)

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

答案 32 :(得分:2)

我认为所有开发人员和DBA所犯的最大错误就是过多地相信约定。我的意思是,惯例只是指导线,大多数情况下都会起作用但不一定总是如此。 我很好的例子是规范化和外键,我知道大多数人都不喜欢这样,但规范化会导致复杂性并导致性能损失,所以如果没有理由将电话号码移到电话桌上,不要这样做它。在外键上,它们对于大多数情况都很好,但是如果你想要创建一些可以在需要时自行工作的东西,外键将来会成为一个问题,而且你也会失去性能。 无论如何,由于我可以指导悲伤的规则和惯例,并且它们应该始终存在但不一定实施,对每个案例的分析应该始终如此。

答案 33 :(得分:2)

当你在开发机器上运行得太快的查询爆炸时,责备db引擎,一旦你在应用程序上抛出一些流量就会窒息。

答案 34 :(得分:2)

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

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

答案 35 :(得分:2)

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

许多开发人员经常没有意识到在开发环境中数据库和应用服务器都在他们的笔记本电脑上 - 但在生产环境中,数据库和应用服务器将在不同的机器上。因此,对于每个查询,在应用服务器和数据库服务器之间传递的数据都有额外的n / w开销。我很惊讶地发现从应用服务器到数据库服务器的数据库调用次数,以便向用户呈现一个页面!

答案 36 :(得分:2)

最大的错误是在代码更新或插入数据时有一个循环,当一个简单的基于集合的解决方案可以更快地完成这个过程,并且更加简单。

答案 37 :(得分:1)

我可以添加一件事,学习使用分析函数,如PARTITION BY,RANK,DENSE_RANK(适用于Oracle)。它们对于复杂查询绝对必不可少。

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

答案 38 :(得分:1)

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

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

请参阅:http://dev.mysql.com/doc/refman/5.1/en/replication-features-functions.html

答案 39 :(得分:1)

1)对如何在Java和数据库之间正确交互的理解不足。

2)过度解析,不正确或不重用SQL

3)未能使用BIND变量

4)当数据库中的SQL集逻辑工作(更好)时,用Java实现过程逻辑。

5)在投入生产之前未能进行任何合理的性能或可扩展性测试

6)使用Crystal Reports并且无法在报告中正确设置模式名称

7)由于忽略了执行计划而使用笛卡尔积实现SQL(你有没看过EXPLAIN PLAN?)