2010-08-20 17 views
2

我不知道我的数据库查询是否完全干净,高效等等。充其量,我可以从数据库中得到我所需要的,但没有其他的。阅读关于编写最佳SQL数据库查询的材料

我应该阅读哪些书籍(或websitse)来推进?我想知道可能进入查询的各种条件和关键字的性能成本(例如,JOIN,IN,WHERE等)。

我在iOS设备上使用SQLite。

回答

10

对于SQLite和/或iOS的具体帮助,这里有一些资源似乎有很好的建议。

现在越来越普遍,要真正做性能调整对于任何企业的数据库系统,下面是我认为重要的是你需要了解的领域:

  • 的基本逻辑数据存储架构您正在使用的系统。例如,b-tree,范围,页面,它们的大小和配置,一次读取多少数据,一行的最大大小(如果这是DBMS中的问题),使用out-of -row数据(如果这是DBMS中的问题)。

  • 表和行数据的索引,约束和基本排序:这些索引的堆,聚簇,非聚簇,唯一性和非唯一性,主键,唯一性约束,包含的列。在所有这些索引中,是否允许空值,只允许一个空值,或者不允许。 Uniqueifiers。覆盖指数。

  • SARGability(查找SARG是“Search ARGument”的缩写)。

  • 外键,默认值,级联删除/更新,它们对插入和删除的影响。

  • NULL是否需要任何存储空间,并且这是否受列位置影响。存储每种数据类型所需的字节数。当尾随空格存储或不存储字符串数据类型时。打包数据类型与非打包数据类型(例如浮点数和小数与整数)。集群索引和非集群索引中的每页行数(或磁盘读取的最小单位)概念。

  • 填充因子,碎片,统计,索引选择性,页面拆分,转发指针。

  • 当“配料”操作可以提高性能和原因时,以及如何最有效地完成操作。

  • INNER,LEFT,RIGHT,FULL和CROSS JOINs。半连接(EXISTS)和反半连接(NOT EXISTS)。任何其他语言特定的语法,例如mySql中的USING和SQL Server中的CROSS APPLY/OUTER APPLY。将连接条件放入外部连接的ON子句与将其放入WHERE子句中的效果。

  • 独立子查询,相关子查询,派生表,公用表表达式,理解EXISTS和NOT EXISTS通常看起来引入了一个相关的子查询,但通常在执行计划中看到的是联接(半或反半联接) 。

  • 查看和理解执行计划以图形或文本。查看CPU的统计信息/配置文件,整个SQL批处理或单个语句使用的读取,写入和持续时间。了解执行的局限性计划&配置文件,这实际上来讲意味着您通常需要使用既优化井。缓存和重用执行计划,从缓存到期计划。参数嗅探和参数化。与这些有关的动态SQL。

  • 将数据类型转换为其他数据类型或仅使用这些数据类型的相对成本。 (例如,一个坚实的经验法则是使用字符串处理比使用数字处理成本更高。)

  • 与基于集合的处理相比,逐行处理的成本通常较高。游标的正确使用(尽管有时需要使用)。函数如何隐藏执行计划成本。书写功能的诱人的陷阱,被调用为每一个问题时可以在套来解决行(虽然这可能会非常棘手,学习如何看,尤其是因为传统的应用程序往往会培养人们认为在这样的功能方面) 。

  • 搜索,扫描,范围扫描,“跳过”扫描。书签查找又称为索引查找,然后使用在索引查找中找到的值将表查找到同一个表。循环,合并和散列连接。渴望&懒惰假脱机。加入订单。估计的行数。实际行数。

  • 当查询太大并且应该使用临时表或其他方法拆分为多个时。

  • 多处理器功能以及并行执行的优点和陷阱。

  • 临时数据库或其他临时文件的使用。生命周期和临时表的范围,表变量(如果你的数据库引擎有这样的话)。是否收集这些统计信息(在SQL Server临时表中使用统计信息和表变量不)。

  • 锁定,锁定粒度,锁定类型,锁定升级,块,死锁。数据访问模式(如先UPDATE,INSERT second,DELETE last)。意图,共享,排他锁。锁定提示(例如,在SQL Server UPDLOCK,HOLDLOCK,READPAST,TABLOCKX中)。

  • 事务和事务隔离。读提交,读取未提交,可重复读取,可序列化,快照,其他我现在不记得了。数据文件,文件组,单独的磁盘,事务日志,简单恢复,完全恢复,最早的打开事务(最小日志序列号(LSN),文件增长)。

  • 序列,数组,列表,标识列,窗口函数,返回的TOP/rownum /限制行数。

  • 物化视图又称为索引视图。计算的列。

  • 1到1,1到0或1,1到很多很多很多。

  • UNION,UNION ALL和其他“垂直”连接。 SQL Server也有EXCEPT和INTERSECT。

  • IN()列表扩展为OR。将IsNull(),Coalesce()或其他空处理机制扩展到CASE语句。

  • 使用DISTINCT“修复”查询而不是处理底层问题的缺陷。

  • 链接服务器如何不通过链接进行连接,对链接服务器的查询通常逐行进行,大量数据可以通过链接进行拉取以在本地执行连接,即使这不是“明智的。

  • 在触发器中执行任何I/O或容易出错的任务的缺陷。触发器的范围(无论它们是针对每一行触发还是针对每个数据操作触发一次)。

  • 使前端,GUI,报告工具或其他客户端执行客户端类型的工作(例如格式化日期或数字作为字符串)而不是数据库引擎。

  • 错误处理。回滚事务以及无论嵌套程度如何都始终回滚到第一个事务,但COMMIT只提供一个级别的工作。

其中大部分与性能有关。有些对性能不太重要,但是(在我看来)如果你想成为一名优秀的SQL开发人员非常重要,因为仅仅拥有快速查询是不够的,他们也需要做对,并与其他人打好关系,并处理错误正确。如果您继续专业地编写SQL并想要改进,那么您最终需要了解大部分这些内容。我将从理解表的组织索引开始,寻求&扫描以及散列/合并/循环联接。我不太了解SQLite,但这些东西对于任何DBMS都是全球性的。

有一件事可以帮助你很多是认识到查询涉及搜索数据,就像你在一个大的电话簿或一系列具有各种各样的电话簿中查找姓名,地址,电话号码和其他东西索引在后面。也许有一个反向电话号码索引或按名字组织的索引。思考从这些物理对象获取信息的最少工作/最短时间路径将帮助您了解查询引擎在选择执行计划时的任务。这种理解能够帮助你说出诸如“等一会儿,为什么它应该在做一个扫描的时候进行扫描?”这个表非常大,并且在X上有一个索引!

示例场景:您的电话簿按照惯例按姓氏组织。您还可以在名字后面加上首字母和姓氏后面的索引,并按名字排序。

任务1:您需要记下名字为Torstein的每个人的所有电话号码。最好的计划:在名字索引中查找5个名字的姓氏,然后在主电话簿中查看这些姓氏。您只是通过对聚簇索引进行书签查找来进行非聚簇索引查找。

任务2:您需要记下名字以A开头的每个人的所有电话号码。快速了解甚至转向名字索引可能没有意义,您可以转到主电话簿,从第1页开始阅读每一页。你只是做了一次表扫描。

为这两项任务选择一个良好的“执行计划”(这就是我们刚才所做的)的本质是你拥有的一些领域知识:你知道Torstein是一个非常罕见的名字,并且可能有数以万计的名字以A开头的人。这个领域知识相当于统计为查询引擎提供的内容。如果没有统计数据,可以选择错误的执行计划

虽然这些常规提示可能并不都适用于iPhone上的SQLite,但在您的脑海中实现这些概念将非常有用,这对您使用SQLite数据库有很大的帮助。无论你使用什么系统,都有一些必然是全局的原则(例如,理解索引永远不会是浪费的努力,因为任何没有索引的系统可能都不值得使用)。

我希望这会有所帮助。随意要求澄清任何一点。如果您在查找资源问题时遇到困难,我会看到我可以指引您的方向。