应用程序开发人员常见的数据库开发错误有哪些?
1. 没有使用合适的索引
这是一个相对简单的问题,但它仍然经常发生。外键上应该有索引。如果你在WHERE中使用一个字段,你应该(可能)在它上面有一个索引。根据需要执行的查询,这样的索引通常应该涵盖多个列。
2. 没有强制引用完整性
您的数据库在这里可能有所不同,但如果您的数据库支持引用完整性(意味着所有外键都保证指向一个存在的实体),那么您应该使用它。
在MySQL数据库中,这种失败是很常见的。我不相信MyISAM支持它。InnoDB。你会发现有些人正在使用MyISAM,有些人正在使用InnoDB,但根本不用它。
更多:
如果我总是用php控制我的数据库输入,像NOT NULL和FOREIGN KEY这样的约束有多重要? 外键在数据库设计中真的有必要吗? 外键在数据库设计中真的有必要吗?
3.使用自然主键而不是代理(技术)主键
自然键是基于(表面上)惟一的外部有意义的数据的键。常见的例子是产品代码、两个字母的州代码(美国)、社会保险号等等。代理键或技术主键是那些在系统之外完全没有意义的键。它们纯粹是为了识别实体而发明的,通常是自动递增的字段(SQL Server, MySQL,其他)或序列(最著名的是Oracle)。
在我看来,您应该始终使用代理键。这个问题出现在以下问题中:
你喜欢你的主键吗? 表中主键的最佳实践是什么? 在这种情况下,您将使用哪种主键格式。 代理键vs.天然/业务键 我应该有一个专用的主键字段吗?
这是一个有点争议的话题,你不会得到普遍的同意。虽然您可能会发现有些人认为自然键在某些情况下是可以的,但您不会发现任何对代理键的批评,除了可以说是不必要的之外。要我说,这是一个很小的缺点。
记住,即使是国家也可能不复存在(例如,南斯拉夫)。
4. 编写需要DISTINCT才能工作的查询
您经常在orm生成的查询中看到这一点。查看Hibernate的日志输出,您将看到所有查询都以以下开头:
SELECT DISTINCT ...
这是一种确保不会返回重复行从而获得重复对象的捷径。你有时也会看到有人这样做。如果你看到太多,那就是一个真正的危险信号。并不是说DISTINCT不好或没有有效的应用程序。它确实(在这两方面),但它不是编写正确查询的替代品或权宜之计。
为什么我讨厌DISTINCT:
什么时候开始变糟了 意见是当一个开发者 建实体查询、加盟 桌子在一起,突然之间 他意识到看起来他是 获取重复的(甚至更多)行 他的直接反应…他的 “解决”这个“问题”的方法就是 抛出DISTINCT关键字和POOF 他所有的烦恼都消失了。
5. 聚合优于连接
数据库应用程序开发人员的另一个常见错误是没有意识到与连接相比,聚合(即GROUP by子句)的开销要高得多。
为了让你知道这个问题有多普遍,我在这里写过几次这个话题,并且因为它而被否决了很多次。例如:
SQL语句- " join " vs " group by and having ":
第一个查询: 选择用户标识 从userrole WHERE roleid IN (1,2,3) 按用户id分组 count (1) = 3 查询时间:0.312 s 第二个查询: 选择t1.userid FROM userrole t1 JOIN userrole t2在t1上。Userid = t2。userid和t2。Roleid = 2 JOIN userrole t3开启t2。Userid = t3。userid和t3。Roleid = 3 和t1。Roleid = 1 查询时间:0.016 s 这是正确的。连接版本I 求婚的速度比 聚合版本。
6. 没有通过视图简化复杂的查询
并不是所有的数据库供应商都支持视图,但对于那些支持视图的供应商,如果使用得当,它们可以极大地简化查询。例如,在一个项目中,我为CRM使用了一个通用的Party模型。这是一种非常强大和灵活的建模技术,但可能导致许多连接。在这个模型中有:
政党:个人和组织; 当事人角色:当事人所做的事情,例如雇员和雇主; 政党角色关系:这些角色如何相互关联。
例子:
泰德是一个人,是一个政党的子类型; 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、表单数据和cookie提供的数据应始终被视为恶意和消毒。确保你得到了你想要的。
8. 不使用准备好的语句
准备语句是指在编译查询时减去插入、更新和WHERE子句中使用的数据,然后再提供这些数据。例如:
SELECT * FROM users WHERE username = 'bob'
vs
SELECT * FROM users WHERE username = ?
or
SELECT * FROM users WHERE username = :username
这取决于你的平台。
我曾看到数据库因为这样做而崩溃。基本上,任何现代数据库每次遇到新的查询都必须编译它。如果它遇到了以前见过的查询,就给了数据库缓存已编译查询和执行计划的机会。通过大量执行查询,可以让数据库有机会发现并相应地进行优化(例如,将编译后的查询固定在内存中)。
使用准备语句还可以提供有关某些查询使用频率的有意义的统计数据。
准备好的语句还可以更好地保护您免受SQL注入攻击。
9. 不够正常化
数据库规范化基本上是优化数据库设计或如何将数据组织到表中的过程。
就在本周,我遇到了一些代码,其中有人将一个数组内爆,并将其插入到数据库中的一个字段中。规范化的方法是将该数组的元素视为子表中的单独行(即一对多关系)。
这也出现在存储用户id列表的最佳方法中:
我在其他系统中看到,列表存储在一个序列化的PHP数组中。
但是,缺乏正常化有多种形式。
更多:
正常化:多远才算够? SQL by Design:为什么需要数据库规范化
10. 过度正常化
这似乎与前面的观点相矛盾,但是正常化,像许多事情一样,是一种工具。它是达到目的的一种手段,本身并不是目的。我认为许多开发者忘记了这一点,开始将“手段”视为“目的”。单元测试就是一个很好的例子。
我曾经工作过一个系统,它为客户端提供了一个巨大的层次结构,大概是这样的:
Licensee -> Dealer Group -> Company -> Practice -> ...
因此,在获得任何有意义的数据之前,您必须将大约11个表连接在一起。这是正常化走得太远的一个很好的例子。
更重要的是,仔细考虑的非正规化可以带来巨大的性能好处,但在这样做时必须非常小心。
更多:
为什么过多的数据库规范化可能是一件坏事 在数据库设计中规范化要走多远? 什么时候不规范化你的SQL数据库 也许正常化并不正常 所有数据库标准化之母关于编码恐怖的争论
11. 使用独占弧
排他弧是一个常见的错误,其中一个表创建了两个或多个外键,其中一个且只有一个外键可以是非空的。大错误。首先,维护数据完整性变得更加困难。毕竟,即使使用引用完整性,也没有什么可以阻止设置两个或多个外键(尽管有复杂的检查约束)。
关系数据库设计实践指南:
我们强烈建议不要在任何地方修建排他性的弧形建筑 有可能,因为它们编写代码时会很尴尬 并造成更多的维护困难。
12. 根本没有对查询进行性能分析
实用主义是至高无上的,尤其是在数据库领域。如果你坚持的原则已经成为教条,那么你很可能已经犯了错误。以上面的聚合查询为例。综合版本可能看起来“不错”,但其性能却很糟糕。一场业绩比较本应结束这场争论(但它并没有),但更重要的是:从一开始就发表这种无知的观点是无知的,甚至是危险的。
13. 过度依赖UNION ALL,特别是UNION结构
在SQL术语中,UNION只是连接一致的数据集,这意味着它们具有相同的类型和列数。它们之间的区别是UNION ALL是一个简单的连接,应该在任何可能的地方被优先使用,而UNION将隐式地执行DISTINCT来删除重复的元组。
工会,像DISTINCT,有他们的位置。有有效的申请。但是如果您发现自己做了很多这样的事情,特别是在子查询中,那么您可能做错了什么。这可能是由于糟糕的查询结构或设计糟糕的数据模型迫使您这样做。
union,特别是在连接或依赖子查询中使用时,可能会削弱数据库。只要有可能就尽量避免。
14. 在查询中使用OR条件
这似乎是无害的。毕竟,and是可以的。OR应该也可以吧?错了。基本上,AND条件限制数据集,而OR条件增长数据集,但不是以一种有利于优化的方式。特别是当不同的OR条件可能相交时,从而迫使优化器有效地对结果进行DISTINCT操作。
Bad:
... 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 Express、MySQL和SQLite,它们可以更好地工作和扩展。应用程序通常需要以意想不到的方式进行扩展。
不对数据库模式使用版本控制 直接针对活动数据库工作 没有阅读和理解更高级的数据库概念(索引、聚集索引、约束、物化视图等) 没有测试可伸缩性……只有3或4行的测试数据永远不会给您真实的实时性能的真实画面
过度使用和/或依赖存储过程。
一些应用程序开发人员将存储过程视为中间层/前端代码的直接扩展。这似乎是微软堆栈开发人员的一个共同特征(我是其中之一,但我已经不再这样做了),并产生许多执行复杂业务逻辑和工作流处理的存储过程。这在其他地方做得更好。
存储过程在某些实际技术因素(例如性能和安全性)需要使用时非常有用。例如,保持大型数据集的聚合/过滤“接近数据”。
我最近不得不帮助维护和增强一个大型Delphi桌面应用程序,其中70%的业务逻辑和规则是在1400个SQL Server存储过程中实现的(其余在UI事件处理程序中)。这是一场噩梦,主要是由于难以将有效的单元测试引入TSQL,缺乏封装和糟糕的工具(调试器,编辑器)。
在过去与Java团队一起工作时,我很快发现在那个环境中,情况往往完全相反。一位Java架构师曾经告诉我:“数据库是用于数据的,而不是用于代码的。”
现在,我认为完全不考虑存储过程是错误的,但在它们提供有用好处的情况下,应该谨慎使用(不是默认情况)(参见其他答案)。
开发人员所犯的关键数据库设计和编程错误
Selfish database design and usage. Developers often treat the database as their personal persistent object store without considering the needs of other stakeholders in the data. This also applies to application architects. Poor database design and data integrity makes it hard for third parties working with the data and can substantially increase the system's life cycle costs. Reporting and MIS tends to be a poor cousin in application design and only done as an afterthought. Abusing denormalised data. Overdoing denormalised data and trying to maintain it within the application is a recipe for data integrity issues. Use denormalisation sparingly. Not wanting to add a join to a query is not an excuse for denormalising. Scared of writing SQL. SQL isn't rocket science and is actually quite good at doing its job. O/R mapping layers are quite good at doing the 95% of queries that are simple and fit well into that model. Sometimes SQL is the best way to do the job. Dogmatic 'No Stored Procedures' policies. Regardless of whether you believe stored procedures are evil, this sort of dogmatic attitude has no place on a software project. Not understanding database design. Normalisation is your friend and it's not rocket science. Joining and cardinality are fairly simple concepts - if you're involved in database application development there's really no excuse for not understanding them.
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,使您的程序员同事能够读懂。
因为“它太神奇了”或“不在我的数据库中”这样的原因,而放弃像Hibernate这样的ORM。 过度依赖像Hibernate这样的ORM,并试图将它硬塞到不合适的地方。
我想补充一点: 偏好“优雅”代码而不是高性能代码。在应用程序开发人员看来,对数据库最有效的代码通常是丑陋的。
Believing that nonsense about premature optimization. Databases must consider performance in the original design and in any subsequent development. Performance is 50% of database design (40% is data integrity and the last 10% is security) in my opinion. Databases which are not built from the bottom up to perform will perform badly once real users and real traffic are placed against the database. Premature optimization doesn't mean no optimization! It doesn't mean you should write code that will almost always perform badly because you find it easier (cursors for example which should never be allowed in a production database unless all else has failed). It means you don't need to look at squeezing out that last little bit of performance until you need to. A lot is known about what will perform better on databases, to ignore this in design and development is short-sighted at best.
这之前已经说过了,但是:索引,索引,还是索引。我见过许多性能不佳的企业web应用程序,它们通过简单地进行一些分析(查看哪些表被频繁访问),然后在这些表上添加索引来解决问题。这甚至不需要太多的SQL编写知识,而且回报是巨大的。
Avoid data duplication like the plague. Some people advocate that a little duplication won't hurt, and will improve performance. Hey, I'm not saying that you have to torture your schema into Third Normal Form, until it's so abstract that not even the DBA's know what's going on. Just understand that whenever you duplicate a set of names, or zipcodes, or shipping codes, the copies WILL fall out of synch with each other eventually. It WILL happen. And then you'll be kicking yourself as you run the weekly maintenance script.
最后:使用清晰、一致、直观的命名约定。与一段编写良好的代码应该是可读的一样,一个好的SQL模式或查询应该是可读的,并且实际上告诉您它在做什么,甚至没有注释。六个月后,当你不得不对桌子进行维护时,你会感谢自己的。“选择account_number, billing_date FROM national_accounts”比“选择ACCNTNBR, BILLDAT FROM NTNLACCTS”更容易使用。
有一件事我想补充,学习使用分析函数,如分区BY, RANK, DENSE_RANK (Oracle)。它们对于复杂的查询是绝对必要的。
其他建议是,如果可能的话,在您的开发团队中有一个专门的数据库开发人员,他应该是SQL、数据库建模、调优等方面的专家(但不是DBA)。这种技能是一笔巨大的财富。
不了解数据库并发模型以及它如何影响开发。事后添加索引和调整查询很容易。然而,应用程序的设计没有适当考虑热点,资源争用 和正确的操作(假设您刚刚阅读的内容仍然有效!)可能需要在数据库和应用层中进行重大更改,以便稍后纠正。
使用Excel存储(大量)数据。
我曾见过一些公司拥有数千行并使用多个工作表(由于以前版本的Excel的行数限制为65535)。
Excel非常适合用于报告、数据演示和其他任务,但不应被视为数据库。
对于基于sql的数据库:
Not taking advantage of CLUSTERED INDEXES or choosing the wrong column(s) to CLUSTER. Not using a SERIAL (autonumber) datatype as a PRIMARY KEY to join to a FOREIGN KEY (INT) in a parent/child table relationship. Not UPDATING STATISTICS on a table when many records have been INSERTED or DELETED. Not reorganizing (i.e. unloading, droping, re-creating, loading and re-indexing) tables when many rows have been inserted or deleted (some engines physically keep deleted rows in a table with a delete flag.) Not taking advantage of FRAGMENT ON EXPRESSION (if supported) on large tables which have high transaction rates. Choosing the wrong datatype for a column! Not choosing a proper column name. Not adding new columns at the end of the table. Not creating proper indexes to support frequently used queries. creating indexes on columns with few possible values and creating unnecessary indexes. ...more to be added.
相关子查询导致的性能差
大多数情况下,您希望避免相关子查询。如果子查询中存在对外部查询的列的引用,则子查询是相关的。当发生这种情况时,对于返回的每一行至少执行一次子查询,如果在应用包含相关子查询的条件之后应用其他条件,则可以执行更多次。
请原谅这个不自然的示例和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
In this example, the query in the from clause is now an inline-view (again some Oracle specific syntax) and is only executed once. Depending on your data model, this query will probably execute much faster. It would perform better than the first query as the number of employees grew. The first query could actually perform better if there were few employees and many stores (and perhaps many of stores had no employees) and the daily_sales table was indexed on store_id. This is not a likely scenario but shows how a correlated query could possibly perform better than an alternative.
我曾多次看到初级开发人员关联子查询,这通常会对性能产生严重影响。但是,当删除一个相关的子查询时,一定要查看之前和之后的解释计划,以确保您没有使性能变差。
如果您正在使用复制(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
不了解DBMS的工作原理。
如果不了解离合器的工作原理,你就不能正确地驾驶变速杆。如果不了解实际上只是在硬盘上写入文件,就无法理解如何使用数据库。
具体地说:
Do you know what a Clustered Index is? Did you think about it when you designed your schema? Do you know how to use indexes properly? How to reuse an index? Do you know what a Covering Index is? So great, you have indexes. How big is 1 row in your index? How big will the index be when you have a lot of data? Will that fit easily into memory? If it won't it's useless as an index. Have you ever used EXPLAIN in MySQL? Great. Now be honest with yourself: Did you understand even half of what you saw? No, you probably didn't. Fix that. Do you understand the Query Cache? Do you know what makes a query un-cachable? Are you using MyISAM? If you NEED full text search, MyISAM's is crap anyway. Use Sphinx. Then switch to Inno.
1)不了解如何正确地在Java和数据库之间进行交互。
2)过度解析,不恰当或没有重用SQL
3)没有使用BIND变量
4)在数据库中使用SQL集逻辑时,用Java实现过程逻辑(更好)。
5)在投入生产前没有进行任何合理的性能或可伸缩性测试
6)使用水晶报表,在报表中没有正确设置模式名
7)由于不了解执行计划,使用笛卡尔式产品实现SQL(你甚至看了EXPLAIN计划吗?)
我不得不说,应用程序开发人员犯的最大错误是没有正确地规范化数据库。
作为一名应用程序开发人员,我意识到正确的数据库结构、规范化和维护的重要性;我花了无数的时间自学数据库结构和管理。根据我的经验,每当我开始与不同的开发人员合作时,我通常必须重组整个数据库并更新应用程序以适应,因为它通常是畸形的和有缺陷的。
For example, I started working with a new project where the developer asked me to implement Facebook Connect on the site. I cracked open the database to see what I had to work with and saw that every little bit of information about any given user was crammed into one table. It took me six hours to write a script that would organize the table into four or five separate tables and another two to get the app to use those tables. Please, normalize your databases! It will make everything else less of a headache.
认为他们是dba和数据建模师/设计人员,而他们在这些领域没有任何正式的灌输。 认为他们的项目不需要DBA,因为这些东西都很简单/琐碎。 未能正确区分应该在数据库中完成的工作和应该在应用程序中完成的工作。 未验证备份,或未备份。 在他们的代码中嵌入原始SQL。
I think the biggest mistakes that all developers and DBAs do is believing too much on conventions. What I mean by that is that convention are only guide lines that for most cases will work but not necessarily always. I great example is normalization and foreign keys, I know most people wont like this, but normalization can cause complexity and cause loss of performance as well, so if there is no reason to move a phone number to a phones table, don't do it. On the foreign keys, they are great for most cases, but if you are trying to create something that can work by it self when needed the foreign key will be a problem in the future, and also you loose performance. Anyways, as I sad rules and conventions are there to guide, and they should always be though of but not necessarily implemented, analysis of each case is what should always be done.
在修复生产数据库内部的一些问题之前没有进行备份。 在存储过程中的存储对象(如表、视图)上使用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开销。我惊奇地发现,为了向用户呈现一个页面,应用程序服务器对数据库服务器进行了大量的数据库调用!
推荐文章
- 不可重复读和幻影读的区别是什么?
- 外键约束:何时使用ON UPDATE和ON DELETE
- 连接查询vs多个查询
- MySQL:在同一个MySQL实例上克隆MySQL数据库
- 优化PostgreSQL进行快速测试
- 表被标记为崩溃,应该修复
- 在Android SQLite中处理日期的最佳方法
- 使用{merge: true}设置的Firestore与更新之间的差异
- mysql_connect():[2002]没有这样的文件或目录(试图通过unix:///tmp/mysql.sock连接)在
- 使用电子邮件地址为主键?
- MongoDB在v4之前不兼容ACID意味着什么?
- 第一次设计数据库:我是否过度设计了?
- 我应该在SQL varchar(长度)中考虑电话的最长的全球电话号码是什么
- MySQL查询转储
- phpMyAdmin错误>格式参数错误?