
sql语句优化的13中方法
1,什么是“执行计划”?
执行计划是数据库根据SQL语句和相关表的统计信息作出的一个查询方案,这个方案是由查询优化器自动分析产生的,比如一条SQL语句如果用来从一个 10万条记录的表中查1条记录,那查询优化器会选择“索引查找”方式,如果该表进行了归档,当前只剩下5000条记录了,那查询优化器就会改变方案,采用 “全表扫描”方式。
可见,执行计划并不是固定的,它是“带有相当个性的”。如何产生一个正确的执行计划呢?
(1) SQL语句是否清晰地告诉查询优化器它想干什么?
(2) 查询优化器得到的数据库统计信息是否是最新的、正确的?
2、 如何写出统一SQL语句
对于以下两句SQL语句,很多人人认为是相同的,但是,数据库查询优化器认为是不同的。
select * from dual
select * From dual
虽然只是大小写不同,查询分析器就认为是两句不同的SQL语句,必须进行两次解析。生成2个执行计划。所以作为程序员,应该保证相同的查询语句在任何地方都一致,多一个空格都不行!
3、 不要把SQL语句写得太长,太过冗余
一般,将一个Select语句的结果作为子集,然后从该子集中再进行查询,这种一层嵌套语句还是比较常见的,但是根据经验,超过3层嵌套,查询优化器就很容易给出错误的执行计划。因为它被绕晕了。像这种类似人工智能的东西,终究比人的分辨力要差些,如果人都看晕了,我可以保证数据库也会晕的。
另外,执行计划是可以被重用的,越简单的SQL语句被重用的可能性越高。而复杂的SQL语句只要有一个字符发生变化就必须重新解析,然后再把这一大堆垃圾塞在内存里。可想而知,数据库的效率会何等低下。
4、考虑使用“临时表”暂存中间结果
简化SQL语句的重要方法就是采用临时表暂存中间结果,但是,临时表的好处远远不止这些,将临时结果暂存在临时表,后面的查询就在tempdb中了,这可以避免程序中多次扫描主表,也大大减少了程序执行中“共享锁”阻塞“更新锁”,减少了阻塞,提高了并发性能。
select * from orderheader where changetime >’2010-10-20 00:00:01′
select * from orderheader where changetime >’2010-09-22 00:00:01′
以上两句语句,查询优化器认为是不同的SQL语句,需要解析两次。如果采用绑定变量
select*from orderheader where changetime >@chgtime
@chgtime变量可以传入任何值,这样大量的类似查询可以重用该执行计划了,可以大大降低数据库解析SQL语句的负担。一次解析,多次重用,是提高数据库效率的原则。
6、 绑定变量窥测
事物都存在两面性,绑定变量对大多数OLTP处理是适用的,但是也有例外。比如在where条件中的字段是“倾斜字段”的时候。
“倾斜字段”指该列中的绝大多数的值都是相同的,比如一张人口调查表,其中“民族”这列,90%以上都是汉族。那么如果一个SQL语句要查询30岁的汉族人口有多少,那“民族”这列必然要被放在where条件中。这个时候如果采用绑定变量@nation会存在很大问题。
试想如果@nation传入的第一个值是“汉族”,那整个执行计划必然会选择表扫描。然后,第二个值传入的是“布依族”,按理说“布依族”占的比例可能只有万分之一,应该采用索引查找。但是,由于重用了第一次解析的“汉族”的那个执行计划,那么第二次也将采用表扫描方式。这个问题就是著名的“绑定变量窥测”,建议对于“倾斜字段”不要采用绑定变量。
7、 只在必要的情况下才使用begin tran
SQL Server中一句SQL语句默认就是一个事务,在该语句执行完成后也是默认commit的。其实,这就是begin tran的一个最小化的形式,好比在每句语句开头隐含了一个begin tran,结束时隐含了一个commit。
有些情况下,我们需要显式声明begin tran,比如做“插、删、改”操作需要同时修改几个表,要求要么几个表都修改成功,要么都不成功。begin tran 可以起到这样的作用,它可以把若干SQL语句套在一起执行,最后再一起commit。 好处是保证了数据的一致性,但任何事情都不是完美无缺的。Begin tran付出的代价是在提交之前,所有SQL语句锁住的资源都不能释放,直到commit掉。
可见,如果Begin tran套住的SQL语句太多,那数据库的性能就糟糕了。在该大事务提交之前,必然会阻塞别的语句,造成block很多。
Begin tran使用的原则是,在保证数据一致性的前提下,begin tran 套住的SQL语句越少越好!有些情况下可以采用触发器同步数据,不一定要用begin tran。
8、 部分SQL查询语句加上nolock
在SQL语句中加nolock是提高SQL Server并发性能的重要手段,在oracle中并不需要这样做,因为oracle的结构更为合理,有undo表空间保存“数据前影”,该数据如果在修改中还未commit,那么你读到的是它修改之前的副本,该副本放在undo表空间中。这样,oracle的读、写可以做到互不影响,这也是oracle 广受称赞的地方。SQL Server 的读、写是会相互阻塞的,为了提高并发性能,对于一些查询,可以加上nolock,这样读的时候可以允许写,但缺点是可能读到未提交的脏数据。使用 nolock有3条原则。
查询的结果用于“插、删、改”的不能加nolock !
查询的表属于频繁发生页分裂的,慎用nolock !
使用临时表一样可以保存“数据前影”,起到类似oracle的undo表空间的功能,能采用临时表提高并发性能的,不要用nolock 。
比如订单表,有订单编号orderid,也有客户编号contactid,那么聚集索引应该加在哪个字段上呢?对于该表,订单编号是顺序添加的,如果在orderid上加聚集索引,新增的行都是添加在末尾,这样不容易经常产生页分裂。然而,由于大多数查询都是根据客户编号来查的,因此,将聚集索引加在contactid上才有意义。而contactid对于订单表而言,并非顺序字段。
比如“张三”的“contactid”是001,那么“张三”的订单信息必须都放在这张表的第一个数据页上,如果今天“张三”新下了一个订单,那该订单信息不能放在表的最后一页,而是第一页!如果第一页放满了呢?很抱歉,该表所有数据都要往后移动为这条记录腾地方。
SQL Server的索引和Oracle的索引是不同的,SQL Server的聚集索引实际上是对表按照聚集索引字段的顺序进行了排序,相当于oracle的索引组织表。SQL Server的聚集索引就是表本身的一种组织形式,所以它的效率是非常高的。也正因为此,插入一条记录,它的位置不是随便放的,而是要按照顺序放在该放的数据页,如果那个数据页没有空间了,就引起了页分裂。所以很显然,聚集索引没有建在表的顺序字段上,该表容易发生页分裂。
曾经碰到过一个情况,一位哥们的某张表重建索引后,插入的效率大幅下降了。估计情况大概是这样的。该表的聚集索引可能没有建在表的顺序字段上,该表经常被归档,所以该表的数据是以一种稀疏状态存在的。比如张三下过20张订单,而最近3个月的订单只有5张,归档策略是保留3个月数据,那么张三过去的 15张订单已经被归档,留下15个空位,可以在insert发生时重新被利用。在这种情况下由于有空位可以利用,就不会发生页分裂。但是查询性能会比较低,因为查询时必须扫描那些没有数据的空位。
重建聚集索引后情况改变了,因为重建聚集索引就是把表中的数据重新排列一遍,原来的空位没有了,而页的填充率又很高,插入数据经常要发生页分裂,所以性能大幅下降。
对于聚集索引没有建在顺序字段上的表,是否要给与比较低的页填充率?是否要避免重建聚集索引?是一个值得考虑的问题!
10、加nolock后查询经常发生页分裂的表,容易产生跳读或重复读
加nolock后可以在“插、删、改”的同时进行查询,但是由于同时发生“插、删、改”,在某些情况下,一旦该数据页满了,那么页分裂不可避免,而此时nolock的查询正在发生,比如在第100页已经读过的记录,可能会因为页分裂而分到第101页,这有可能使得nolock查询在读101页时重复读到该条数据,产生“重复读”。同理,如果在100页上的数据还没被读到就分到99页去了,那nolock查询有可能会漏过该记录,产生“跳读”。
上面提到的哥们,在加了nolock后一些操作出现报错,估计有可能因为nolock查询产生了重复读,2条相同的记录去插入别的表,当然会发生主键冲突。
11、合理使用like模糊查询
有的时候会需要进行一些模糊查询比如:
select * from contact where username like ‘%yue%’
关键词 %yue%,由于yue前面用到了“%”,因此该查询必然走全表扫描,除非必要,否则不要在关键词前加%
12、数据类型的隐式转换对查询效率的影响
sql server2000的数据库,我们的程序在提交sql语句的时候,没有使用强类型提交这个字段的值,由sql server 2000自动转换数据类型,会导致传入的参数与主键字段类型不一致,这个时候sql server 2000可能就会使用全表扫描。Sql server2005上没有发现这种问题,但是还是应该注意一下。
13、SQL Server 表连接的三种方式
Merge Join
Nested Loop Join
Hash Join
SQL Server 2000只有一种join方式——Nested Loop Join,如果A结果集较小,那就默认作为外表,A中每条记录都要去B中扫描一遍,实际扫过的行数相当于A结果集行数x B结果集行数。所以如果两个结果集都很大,那Join的结果很糟糕。
SQL Server 2005新增了Merge Join,如果A表和B表的连接字段正好是聚集索引所在字段,那么表的顺序已经排好,只要两边拼上去就行了,这种join的开销相当于A表的结果集行数加上B表的结果集行数,一个是加,一个是乘,可见merge join 的效果要比Nested Loop Join好多了。
数据分析咨询请扫描二维码
若不方便扫码,搜微信号:CDAshujufenxi
解析 loss.backward ():深度学习中梯度汇总与同步的自动触发核心 在深度学习模型训练流程中,loss.backward()是连接 “前向计算 ...
2025-09-02要解答 “画 K-S 图时横轴是等距还是等频” 的问题,需先明确 K-S 图的核心用途(检验样本分布与理论分布的一致性),再结合横轴 ...
2025-09-02CDA 数据分析师:助力企业破解数据需求与数据分析需求难题 在数字化浪潮席卷全球的当下,数据已成为企业核心战略资产。无论是市 ...
2025-09-02Power BI 度量值实战:基于每月收入与税金占比计算累计税金分摊金额 在企业财务分析中,税金分摊是成本核算与利润统计的核心环节 ...
2025-09-01巧用 ALTER TABLE rent ADD INDEX:租房系统数据库性能优化实践 在租房管理系统中,rent表是核心业务表之一,通常存储租赁订单信 ...
2025-09-01CDA 数据分析师:企业数字化转型的核心引擎 —— 从能力落地到价值跃迁 当数字化转型从 “选择题” 变为企业生存的 “必答题”, ...
2025-09-01数据清洗工具全景指南:从入门到进阶的实操路径 在数据驱动决策的链条中,“数据清洗” 是决定后续分析与建模有效性的 “第一道 ...
2025-08-29机器学习中的参数优化:以预测结果为核心的闭环调优路径 在机器学习模型落地中,“参数” 是连接 “数据” 与 “预测结果” 的关 ...
2025-08-29CDA 数据分析与量化策略分析流程:协同落地数据驱动价值 在数据驱动决策的实践中,“流程” 是确保价值落地的核心骨架 ——CDA ...
2025-08-29CDA含金量分析 在数字经济与人工智能深度融合的时代,数据驱动决策已成为企业核心竞争力的关键要素。CDA(Certified Data Analys ...
2025-08-28CDA认证:数据时代的职业通行证 当海通证券的交易大厅里闪烁的屏幕实时跳动着市场数据,当苏州银行的数字金融部连夜部署新的风控 ...
2025-08-28PCU:游戏运营的 “实时晴雨表”—— 从数据监控到运营决策的落地指南 在游戏行业,DAU(日活跃用户)、MAU(月活跃用户)是衡量 ...
2025-08-28Excel 聚类分析:零代码实现数据分群,赋能中小团队业务决策 在数字化转型中,“数据分群” 是企业理解用户、优化运营的核心手段 ...
2025-08-28CDA 数据分析师:数字化时代数据思维的践行者与价值推动者 当数字经济成为全球经济增长的核心引擎,数据已从 “辅助性信息” 跃 ...
2025-08-28ALTER TABLE ADD 多个 INDEX:数据库批量索引优化的高效实践 在数据库运维与性能优化中,索引是提升查询效率的核心手段。当业务 ...
2025-08-27Power BI 去重函数:数据清洗与精准分析的核心工具 在企业数据分析流程中,数据质量直接决定分析结果的可靠性。Power BI 作为主 ...
2025-08-27CDA 数据分析师:数据探索与统计分析的实践与价值 在数字化浪潮席卷各行业的当下,数据已成为企业核心资产,而 CDA(Certif ...
2025-08-27t 检验与 Wilcoxon 检验:数据差异比较的两大统计利器 在数据分析中,“比较差异” 是核心需求之一 —— 如新药疗效是否优于旧药 ...
2025-08-26季节性分解外推法:解锁时间序列预测的规律密码 在商业决策、资源调度、政策制定等领域,准确的预测是规避风险、提升效率的关键 ...
2025-08-26CDA 数据分析师:数据治理驱动下的企业数据价值守护者 在数字经济时代,数据已成为企业核心战略资产,其价值的释放离不开高 ...
2025-08-26