当前位置:主页 > 计算机电子书 > 数据库 > SQL代码下载
Effective SQL:编写高质量SQL语句的61个有效方法

Effective SQL:编写高质量SQL语句的61个有效方法 PDF 影印版

  • 更新:2019-05-24
  • 大小:169.2 MB
  • 类别:SQL代码
  • 作者:约翰
  • 出版:机械工业出版社
  • 格式:PDF

  • 资源介绍
  • 相关推荐

Effective SQL:编写高质量SQL语句的61个有效方法

Effective SQL:编写高质量SQL语句的61个有效方法

内容总结

SQL语句编写注意问题
下面就某些SQL语句编写注意问题做一下详细的介绍。在这些where子句中,即使某些列存在索引,但是由于编写了劣质的SQL,系统在运行该SQL语句时也不能使用该索引,而同样使用全表扫描,这就造成了响应速度的极大降低。

1.IS NULL 与 IS NOT NULL
不能用null作索引,任何包含null值的列都将不会被包含在索引中。即使索引有多列这样的情况下,只要这些列中有一列含有null,该列就会从索引中排除。也就是说如果某列存在空值,即使对该列建索引也不会提高性能。
任何在where子句中使用is null或is not null的语句优化器是不允许使用索引的。

2.避免使用不兼容的数据类型。
不兼容的数据类型代表着全表检索数据的类型转换,访问将变为全表扫描
select * from employee where last_name = 100;注last_name为varchar类型

3.联接列
对于有联接的列,即使最后的联接值为一个静态值,优化器是不会使用索引的。我们一起来看一个例子,假定有一个职工表(employee),对于 一个职工的姓和名分成两列存放(FIRST_NAME和LAST_NAME),现在要查询一个叫比尔.克林顿(Bill Cliton)的职工。
下面是一个采用联接查询的SQL语句,
select * from employss where first_name||''||last_name ='Beill Cliton';
上面这条语句完全可以查询出是否有Bill Cliton这个员工,但是这里需要注意,系统优化器对基于last_name创建的索引没有使用。
当采用下面这种SQL语句的编写,Oracle系统就可以采用基于last_name创建的索引。
*** where first_name ='Beill' and last_name ='Cliton';

4. 通配符(%)开头的like语句
目前的需求是这样的,要求在职工表中查询名字中包含cliton的人。可以采用如下的查询SQL语句:
select * from employee where last_name like '%cliton%'这里由于通配符(%)在搜寻词首出现,所以Oracle系统不使用last_name的索引。然而当通配符出现在字符串其他位置时,优化器就能利用索引。在下面的查询中索引得到了使用:
select * from employee where last_name like 'c%'

5.索引字段上进行运算会使索引失效。
尽量避免在WHERE子句中对字段进行函数或表达式操作,这将导致引擎放弃使用索引而进行全表扫描。
eg:SELECT * FROM T1 WHERE F1/2=100 应改为: SELECT * FROM T1 WHERE F1=100*2

6. Order by语句
ORDER BY语句决定了Oracle如何将返回的查询结果排序。Order by语句对要排序的列没有什么特别的限制,也可以将函数加入列中(象联接或者附加等)。任何在Order by语句的非索引项或者有计算表达式都将降低查询速度。
仔细检查order by语句以找出非索引项或者表达式,它们会降低性能。解决这个问题的办法就是重写order by语句以使用索引,也可以为所使用的列建立另外一个索引,同时应绝对避免在order by子句中使用表达式。

7. NOT
我们在查询时经常在where子句使用一些逻辑表达式,如大于、小于、等于以及不等于等等,也可以使用and(与)、or(或)以及not(非)。NOT可用来对任何逻辑运算符号取反。下面是一个NOT子句的例子:
... where not (status ='VALID')
如果要使用NOT,则应在取反的短语前面加上括号,并在短语前面加上NOT运算符。NOT运算符包含在另外一个逻辑运算符中,这就是不等于(<>)运算符。换句话说,即使不在查询where子句中显式地加入NOT词,NOT仍在运算符中,见下例:
... where status <>'INVALID';
对这个查询,可以改写为不使用NOT:
select * from employee where salary<3000 or salary>3000;
虽然这两种查询的结果一样,但是第二种查询方案会比第一种查询方案更快些。第二种查询允许Oracle对salary列使用索引,而第一种查询则不能使用索引。

8. IN和EXISTS
有时候会将一列和一系列值相比较。最简单的办法就是在where子句中使用子查询。在where子句中可以使用两种格式的子查询。
第一种格式是使用IN操作符:
... where column in(select * from ... where ...);
第二种格式是使用EXIST操作符:
... where exists (select 'X' from ...where ...);
我相信绝大多数人会使用第一种格式,因为它比较容易编写,而实际上第二种格式要远比第一种格式的效率高。在Oracle中可以几乎将所有的IN操作符子查询改写为使用EXISTS的子查询。
第二种格式中,子查询以‘select 'X'开始。运用EXISTS子句不管子查询从表中抽取什么数据它只查看where子句。这样优化器就不必遍历整个表而仅根据索引就可完成工作(这里假定在where语句中使用的列存在索引)。相对于IN子句来说,EXISTS使用相连子查询,构造起来要比IN子查询困难一些。
通过使用EXIST,Oracle系统会首先检查主查询,然后运行子查询直到它找到第一个匹配项,这就节省了时间。Oracle系统在执行IN子查询时,首先执行子查询,并将获得的结果列表存放在一个加了索引的临时表中。在执行子查询之前,系统先将主查询挂起,待子查询执行完毕,存放在临时表中以后再执行主查询。这也就是使用EXISTS比使用IN通常查询速度快的原因。
同时应尽可能使用NOT EXISTS来代替NOT IN,尽管二者都使用了NOT(不能使用索引而降低速度),NOT EXISTS要比NOT IN查询效率更高。

9.应尽量避免在 where 子句中使用or来连接条件,否则将导致引擎放弃使用索引而进行全表扫描,
如:select id from employee where num=10 or num=20
可以这样查询:select id from employee where num=10 union all select id from employeewhere num=20

10.应尽量避免在 where 子句中对字段进行表达式操作
这将导致引擎放弃使用索引而进行全表扫描。如:select id from t where num/2=100应改为:select id from t where num=100*2

内容介绍

本书结合SQL实践与实际案例,整合了实用的解决方案与洞见,可帮助大家解决复杂的问题,设计出能简化数据管理的数据库。作者拥有担任世界*数据库顾问与讲师的丰富经验,在本书中归纳了编写高质量SQL语句的61个具体方法,并提供不同SQL版本的差异详情,无论你使用何种SQL版本都能从中获益。书中提供了大量清晰、务实的解释,以及专家的建议与大量实用的代码。本书除了介绍语法之外,还会讨论数据库设计的佳实践、层次结构管理与元数据等议题。若你对SQL已经有基本的认识,本书将能帮助你成为解决SQL问题的专家。书中内容涵盖各种SQL版本:IBMDB2、MicrosoftAccess、MicrosoftSQLServer、MySQL、OracleDatabase与PostgreSQL。

目录

  • 本书赞誉
  • 译者序
  • 前言
  • 致谢
  • 关于作者
  • 关于技术编辑
  • 第1章 数据模型设计1
  • 第1条:确保所有表都有主键1
  • 第2条:避免存储冗余数据4
  • 第3条:消除重复数据组7
  • 第4条:每列只存储一个属性9
  • 第5条:理解为什么存储计算列通常有害无益13
  • 第6条:定义外键以确保引用完整性16
  • 第7条:确保表间关系的合理性19
  • 第8条:当第三范式不够时,采用更多范式22
  • 第9条:非规范化数据仓库27
  • 第2章 可编程性与索引设计30
  • 第10条:创建索引时空值的影响30
  • 第11条:创建索引时谨慎考虑以最小化索引和数据扫描35
  • 第12条:索引不只是过滤37
  • 第13条:不要过度使用触发器41
  • 第14条:使用过滤索引包含或排除数据子集45
  • 第15条:使用声明式约束替代编码校验47
  • 第16条:了解数据库使用的SQL方言并编写相应的代码48
  • 第17条:了解何时在索引中使用计算结果51
  • 第3章 当你不能改变设计时55
  • 第18条:使用视图来简化不能更改的内容55
  • 第19条:使用ETL将非关系数据转换为有用的信息60
  • 第20条:创建汇总表并维护64
  • 第21条:使用UNION语句将非规范化数据列转行66
  • 第4章 过滤与查找数据72
  • 第22条:了解关系代数及其如何在SQL中实现72
  • 第23条:查找不匹配或缺失的记录78
  • 第24条:了解何时使用CASE解决问题79
  • 第25条:了解解决多条件查询的技术83
  • 第26条:如需完美匹配,先对数据进行除操作88
  • 第27条:如何按时间范围正确地过滤日期和时间的列91
  • 第28条:书写可参数化搜索的查询以确保引擎使用索引94
  • 第29条:正确地定义“左”连接的“右”侧97
  • 第5章 聚合100
  • 第30条:理解GROUP BY的工作原理100
  • 第31条:简化GROUP BY子句106
  • 第32条:利用GROUP BY或HAVING解决复杂的问题109
  • 第33条:避免使用GROUP BY来查找最大值或最小值113
  • 第34条:使用OUTER JOIN时避免获取错误的COUNT()117
  • 第35条:测试HAVING COUNT(x) <某数时包含零值记录121
  • 第36条:使用DISTINCT获取不重复的计数123
  • 第37条:知道如何使用窗口函数126
  • 第38条:创建行号与排名129
  • 第39条:创建可移动聚合函数131
  • 第6章 子查询136
  • 第40条:了解在何处使用子查询136
  • 第41条:了解关联和非关联子查询的差异140
  • 第42条:尽可能使用公共表表达式而不是子查询145
  • 第43条:使用连接而非子查询创建更高效的查询151
  • 第7章 获取与分析元数据154
  • 第44条:了解如何使用系统的查询分析器154
  • 第45条:学习获取数据库的元数据164
  • 第46条:理解执行计划的工作原理168
  • 第8章 笛卡儿积175
  • 第47条:生成两张表所有行的组合并标示一张表中间接关联另一张表的列175
  • 第48条:理解如何以等分量排名177
  • 第49条:知道如何对表中的行配对181
  • 第50条:理解如何列出类别与前三偏好185
  • 第9章 计数表189
  • 第51条:根据计数表内定义的参数生成空行189
  • 第52条:使用计数表和窗口函数生成序列193
  • 第53条:根据计数表内定义的范围生成行196
  • 第54条:根据计数表定义的值范围转换某个表中的值199
  • 第55条:使用日期表简化日期计算205
  • 第56条:创建在某个范围内所有日期的日程表209
  • 第57条:使用计数表行转列212
  • 第10章 层次数据建模217
  • 第58条:从邻接列表模型开始218
  • 第59条:对不常更新的数据使用嵌套集以提升查询性能220
  • 第60条:使用存储路径简化设置与搜索222
  • 第61条:使用祖先遍历闭包做复杂搜索224
  • 附录 日期与时间类型、运算符和函数228

资源下载

资源下载地址1:https://pan.baidu.com/s/12h5KKjSnAFqjvfyizljPgQ

相关资源

网友留言

网友NO.28272
师慧英

通过这些查询优化方法,我们设法将查询从8秒降低到2秒,并且将查询次数从4次减少到1次。需要说明的是,这些查询时间是在我们开发环境运行时记录的,生产环境速度会更快。 这对追踪查询缓慢及其修复等问题是一个有用的指南。优化查询看起来可能像一个可怕的任务,但只要你尝试一下,并取得一些初步的胜利,你就会开始找到错误,并希望做出进一步改善。

网友NO.43329
董雅韶

统一SQL语句的写法 对于以下两句SQL语句,程序员认为是相同的,数据库查询优化器认为是不同的。 select*from dual select*From dual 其实就是大小写不同,查询分析器就认为是两句不同的SQL语句,必须进行两次解析。生成2个执行计划。所以作为程序员,应该保证相同的查询语句在任何地方都一致,多一个空格都不行!