如何编写更好的SQL查询:终极指南-第二部分
本文参考文章:http://www.kdnuggets.com/2017/08/write-better-sql-queries-definitive-guide-part-2.html
转载请注明出自:葡萄城官网,葡萄城为开发者提供专业的开发工具、解决方案和服务,赋能开发者。

上一篇文章中,我们学习了 SQL 查询是如何执行的以及在编写 SQL 查询语句时需要注意的地方。
下面,我进一步学习查询方法以及查询优化。
基于集合和程序的方法进行查询
反向模型中隐含的事实是,建立查询时基于集合和程序的方法之间存在着不同。
- 查询的程序方法是一种非常类似于编程的方法:你告诉系统需要做些什么以及如何做。例如上一篇文章中的示例,通过执行一个函数然后调用另一个函数来查询数据库,或者使用包含循环、条件和用户定义函数(UDF)的逻辑方式来获得最终查询结果。你会发现通过这种方式,一直在请求一层一层中数据的子集。这种方法也经常被称为逐步或逐行查询。
- 另一种是基于集合的方法,只需指定需要执行的操作。使用这种方法要做的事情就是,指定你想通过查询获得的结果的条件和要求。在检索数据过程中,你不需要关注实现查询的内部机制:数据库引擎会决定最佳的执行查询的算法和逻辑。
由于 SQL 是基于集合的,所以这种方法比起程序方法更加有效,这也解释了为什么在某些情况下,SQL 可以比代码工作地更快。
基于集合的查询方法也是数据挖掘分析行业要求你必须掌握的技能!因为你需要熟练的在这两种方法之间进行切换。如果你发现自己的查询中存在程序查询,则应该考虑是否需要重写这部分。
从查询到执行计划
反向模式不是静止不变的。在你成为 SQL 开发者的过程中,避免查询反向模型和重写查询可能会是一个很艰难的任务。所以时常需要使用工具以一种更加结构化的方法来优化你的查询。
对性能的思考不仅需要更结构化的方法,还需要更深入的方法。
然而,这种结构化和深入的方法主要是基于查询计划的。查询计划首先被解析为“解析树”并且准确定义了每个操作使用什么算法以及如何协调操作过程。
查询优化
在优化查询时,很可能需要手动检查优化器生成的计划。在这种情况下,将需要通过查看查询计划来再次分析你的查询。
要掌握这样的查询计划,你需要使用一些数据库管理系统提供给你的工具。你可以使用以下的一些工具:
- 一些软件包功能工具可以生成查询计划的图形表示。
- 其它工具能够为你提供查询计划的文本描述。
请注意,如果你正在使用 PostgreSQL,则可以区分不同的 EXPLAIN,你只需获取描述,说明 planner 如何在不运行计划的情况下执行查询。同时 EXPLAIN ANALYZE 会执行查询,并返回给你一个评估查询计划与实际查询计划的分析报告。一般来说,实际执行计划会切实的执行这个计划,而评估执行计划可以在不执行查询的情况下,解决这个问题。在逻辑上,实际执行计划更为有用,因为它包含了执行查询时,实际发生的其它细节和统计信息。
接下来你将了解 XPLAIN 和 ANALYZE 的更多信息,以及如何使用这两个命令来进一步了解你的查询计划和查询性能。要做到这一点,你需要开始使用两个表: one_million 和 half_million 来做一些示例。
你可以借助 EXPLAIN 来检索 one_million 表的当前信息:确保已将其放在运行查询的首要位置,在运行完成之后,会返回到查询计划中:
EXPLAIN
SELECT *
FROM one_million;
QUERY PLAN
_________________________________________________
Seq Scan on one_million
(cost=0.00..18584.82 rows=1025082 width=36)
(1 row)
在以上示例中,我们看到查询的 Cost 是0.00..18584.82 ,行数是1025082,列宽是36。
同时,也可以借助 ANALYZE 来更新统计信息 。
ANALYZE one_million;
EXPLAIN
SELECT *
FROM one_million;
QUERY PLAN
_________________________________________________
Seq Scan on one_million
(cost=0.00..18334.00 rows=1000000 width=37)
(1 row)
除了 EXPLAIN 和 ANALYZE,你也可以借助 EXPLAIN ANALYZE 来检索实际执行时间:
EXPLAIN ANALYZE
SELECT *
FROM one_million;
QUERY PLAN
___________________________________________________
Seq Scan on one_million
(cost=0.00..18334.00 rows=1000000 width=37)
(actual time=0.015..1207.019 rows=1000000 loops=1)
Total runtime: 2320.146 ms
(2 rows)
使用 EXPLAIN ANALYZE 的缺点就是需要实际执行查询,这点值得注意!
到目前为止,我们看到的所有算法是顺序扫描或全表扫描:这是一种在数据库上进行扫描的方法,扫描的表的每一行都是以顺序(串行)的顺序进行读取,每一列都会检查是否符合条件。在性能方面,顺序扫描不是最佳的执行计划,因为需要扫描整个表。但是如果使用慢磁盘,顺序读取也会很快。
还有一些其它算法的示例:
EXPLAIN ANALYZE
SELECT *
FROM one_million JOIN half_million
ON (one_million.counter=half_million.counter);
QUERY PLAN
_____________________________________________________________
Hash Join (cost=15417.00..68831.00 rows=500000 width=42)
(actual time=1241.471..5912.553 rows=500000 loops=1)
Hash Cond: (one_million.counter = half_million.counter)
-> Seq Scan on one_million
(cost=0.00..18334.00 rows=1000000 width=37)
(actual time=0.007..1254.027 rows=1000000 loops=1)
-> Hash (cost=7213.00..7213.00 rows=500000 width=5)
(actual time=1241.251..1241.251 rows=500000 loops=1)
Buckets: 4096 Batches: 16 Memory Usage: 770kB
-> Seq Scan on half_million
(cost=0.00..7213.00 rows=500000 width=5)
(actual time=0.008..601.128 rows=500000 loops=1)
Total runtime: 6468.337 ms
我们可以看到查询优化器选择了 Hash Join。请记住这个操作,因为我们需要使用这个来评估查询的时间复杂度。我们注意到了上面示例中没有 half_million.counter 索引,我们可以在下面示例中添加索引 :
CREATE INDEX ON half_million(counter);
EXPLAIN ANALYZE
SELECT *
FROM one_million JOIN half_million
ON (one_million.counter=half_million.counter);
QUERY PLAN
______________________________________________________________
Merge Join (cost=4.12..37650.65 rows=500000 width=42)
(actual time=0.033..3272.940 rows=500000 loops=1)
Merge Cond: (one_million.counter = half_million.counter)
-> Index Scan using one_million_counter_idx on one_million
(cost=0.00..32129.34 rows=1000000 width=37)
(actual time=0.011..694.466 rows=500001 loops=1)
-> Index Scan using half_million_counter_idx on half_million
(cost=0.00..14120.29 rows=500000 width=5)
(actual time=0.010..683.674 rows=500000 loops=1)
Total runtime: 3833.310 ms
(5 rows)
通过创建索引,查询优化器已经决定了索引扫描时,如何查找 Merge join。
请注意,索引扫描和全表扫描(顺序扫描)之间的区别:后者(也称为“表扫描”)是通过扫描所有数据或索引所有页面来查找到适合的结果,而前者只扫描表中的每一行。
教程的第二部分内容,就介绍到这里。后续还会有《如何编写更好的SQL查询》系列的最后一篇文章,敬请期待。
相关阅读:
迁移 SQL Server 数据库到 Azure SQL 实战
如何编写更好的SQL查询:终极指南-第二部分的更多相关文章
- 如何编写更好的SQL查询:终极指南-第三部分
本次我们学习<如何编写更好的SQL查询>系列的最后一篇文章. 时间复杂度和大O符号 通过前两篇文章,我们已经对查询计划有了一定了解.接下来,我们还可以借助计算复杂度理论,来进一步深入地挖掘 ...
- 如何编写更好的SQL查询:终极指南-第一部分
结构化查询语言(SQL)是数据挖掘分析行业不可或缺的一项技能,总的来说,学习这个技能是比较容易的.对于SQL来说,编写查询语句只是第一步,确保查询语句高效并且适合于你的数据库操作工作,才是最重要的.这 ...
- 每周一书《Oracle 12 c PL(SQL)程序设计终极指南》
本周为大家送出的书是<Oracle 12 c PL(SQL)程序设计终极指南>,此书由机械工业出版社出版, 孙风栋,王澜,郭晓惠 著. 内容简介: <Oracle 12c PL/SQ ...
- sql查询技巧指南
传送门(牛客网我做过的每到题目答案以及解析) sql定义: 结构化查询语言(Structured Query Language)简称SQL,是一种特殊目的的编程语言,是一种数据库查询和程序设计语言,用 ...
- 记一个简单的sql查询
在我们做各类统计和各类报表的时候,会有各种各样的查询要求.条件 这篇主要记录一个常见的统计查询 要求如下: 统计一段时间内,每天注册人数,如果某天没有人注册则显示为0 现在建个简单的表来试试 建表语句 ...
- 一个能够编写、运行SQL查询并可视化结果的Web应用:SqlPad
SqlPad 是一个能够用于编写.运行 SQL 查询并可视化结果的 Web 应用.支持 PostgreSQL.MySQL 和 SQL Server.SqlPad 目前仅适合单个团队在内网中使用,它直接 ...
- Hibernate通过自编写sql查询
public List<InterProductMsg> selectIsHaveProductid(String productId) { String sql="SELECT ...
- Hibernate SQL查询 addScalar()或addEntity()
本文完全引用自: http://www.cnblogs.com/chenyixue/p/5601285.html Hibernate除了支持HQL查询外,还支持原生SQL查询. 对原 ...
- Hibernate原生SQL查询
最近在做一个较为复杂的查询,hibernate基本的查询不能满足,只好使用其提供的原生sql查询.参考网上的一些资料,做一些总结. 对原生SQL查询执行的控制是通过SQLQuery接口进行的,通过执行 ...
随机推荐
- MySQL慢查询日志分析
一:查询slow log的状态,如示例代码所示,则slow log已经开启. mysql> show variables like '%slow%'; +-------------------- ...
- express 最佳实践(二):中间件
express 最佳实践(二):中间件 第一篇 express 最佳实践(一):项目结构 express 中最重要的就是中间件了,可以说中间件组成了express,中间件就是 express 的核心. ...
- (转)Vi命令详解
vi编辑器是所有Unix及Linux系统下标准的编辑器,它的强大不逊色于任何最新的文本编辑器,这里只是简单地介绍一下它的用法和一小部分指令.由于对Unix及Linux系统的任何版本,vi编辑器是完全相 ...
- Java 简单的 socket 编程入门实战
这个是给女朋友写的:) 首先需要知道我们每个电脑都可以成为server(服务器) 和 client(客户端) 我们需要使用java来实现客户端与服务器的数据传输 先帖上代码 注意这里两张代码处于两个j ...
- Nlpir Parser敏感词搜索灵玖语义技术应用
近年来随着网络技术的飞速发展和用户的剧烈增长,网络传输数据量越来越大,网络用语越来越趋于多样化.如何快速的屏蔽用户的不当言论.过滤用户发表内容中的非法词汇已成为关键词匹配领域的一项重大难题. 目前主要 ...
- SSE再学习:灵活运用SIMD指令6倍提升Sobel边缘检测的速度(4000*3000的24位图像时间由180ms降低到30ms)。
这半年多时间,基本都在折腾一些基本的优化,有很多都是十几年前的技术了,从随大流的角度来考虑,研究这些东西在很多人看来是浪费时间了,即不能赚钱,也对工作能力提升无啥帮助.可我觉得人类所谓的幸福,可以分为 ...
- RabbitMQ入门与使用篇
介绍 RabbitMQ是一个由erlang开发的基于AMQP(Advanced Message Queue)协议的开源实现.用于在分布式系统中存储转发消息,在易用性.扩展性.高可用性等方面都非常的优秀 ...
- Cognos配置管理
--Cognos配置管理 --------------------------2014/03/19 进入配置管理界面: /washome/cognos/c10/bin64 ./cogconfig.sh ...
- SK-Learn 全家福
SK-Learn API 全家福 最近SK-Learn用的比较多, 以后也会经常用,将Sk-Learn 所有内容整理了一下,整理思路,并可以备查. (高清图片可以用鼠标右键在单独窗口打开,或者保存到本 ...
- HTML颜色代码表/颜色名(网摘)
HTML颜色代码表 原文出处:[颜色代码] HTML颜色名 source link: http://www.runoob.com/html/html-colornames.html