草庐IT

sql语句优化

马玲 2023-08-27 原文

问题查找及措施

问题查找

  1. 需要找到具体的代码,对其进行一对一优化,而非一直把关注点放在服务器和sql平台
  2. 降低简化每个事务中处理的问题,尽量不要让一个事务拖太长的时间

例如文件上传时,应将文件上传这一步放在事务外面

  1. 微软建议

 

 

4.启动sql定时执行计划

怎么启动sqlserver代理服务-百度经验 (baidu.com)

 

 

  1. 启动SQL Server Profiler,获取耗时语句
  2. 部分语句可使用[数据库引擎优化顾问]获取优化意见。(存储过程是不能的)

措施

  • 首先你要知道是否跟sql语句有关,确保不是机器开不开机,服务器硬件配置太差
  • 接着使用sql性能检测工具--sql server profiler,分析出sql慢的相关语句,就是执行时间过长,占用系统资源,cpu过多的
  • 通过下文《sql优化方法跟技巧》,避免一些不合理的sql语句,取暂优sql
  • 再然后判断是否使用了合理的统计信息。sql server中可以自动统计表中的数据分布信息,定时根据数据情况,更新统计信息,是很有必要的
  • 确认表中使用了合理的索引,见下文《索引》
  • 数据太多的表,要分区,缩小查找范围

 

相关资料来源

sql语句的优化分析 - 张龙豪 - 博客园 (cnblogs.com)

sql优化(原理,方法,特点,实例) - -涂涂- - 博客园 (cnblogs.com)

sql优化方法跟技巧

select优化

1.保证不查询多余的列与行。

  • 尽量避免select * 的存在,使用具体的列代替*,避免多余的列
  • 使用where限定具体要查询的数据,避免多余的行
  • 使用top,distinct关键字减少多余重复的行

2.慎用distinct关键字

distinct在查询一个字段或者很少字段的情况下使用,会避免重复数据的出现,给查询带来优化效果。

但是查询字段很多的情况下使用,则会大大降低查询效率

3.慎用union关键字

使用union all能对union进行一定的优化

4.判断表中是否存在数据

禁用*号查数量,查是否存在:select count(*) from product

可以用:select top(1) id from product。查是否存在

  1. 6.       连接查询的优化

减少连接表的数据数量可以提高效率

  1. 少使用like,及时要用可以仅在后面加一个%
  2. 复杂的运算,等取出来到客户端后再处理
  3. 尽量使用多表查询代替子查询
  4. Order by 的列最好是索引列,最好不要是可为空的列。但是注意日期列不适合建索引。
  5. 排序影响性能(测试,如果优化了,写成通用的测C#)
  6. 先进行小表连接再大表
  7. 尽量减少直接的运算
14. 当在SQL语句中连接多个表时, 请使用表的别名并把别名前缀于每个Column上.这样一来,就可以减少解析的时间并减少那些由Column歧义引起的语法错误。

Where优化

1.  用EXISTS替代IN、用NOT EXISTS替代NOT IN:

(高效)SELECT * FROM  EMP (基础表)  WHERE  EMPNO > 0  AND  EXISTS (SELECT ‘X'  FROM DEPT  WHERE  DEPT.DEPTNO = EMP.DEPTNO  AND  LOC = ‘MELB')

 (低效)SELECT  * FROM  EMP (基础表)  WHERE  EMPNO > 0  AND  DEPTNO IN(SELECT DEPTNO  FROM  DEPT  WHERE  LOC = ‘MELB')

 
2.  IS NULL 或IS NOT NULL操作(判断字段是否为空):用其它相同功能的操作运算代替,如:a is not null 改为 a>0 或a>’’等。不允许字段为空,而用一个缺省值代替空值,如申请中状态字段不允许为空,缺省为申请。
3.  Where后面条件的顺序,将可以能更多排除数据减少数据量的条件放在最前面
4.  用EXISTS替换DISTINCT:

(低效): SELECT  DISTINCT  DEPT_NO,DEPT_NAME  FROM  DEPT D , EMP E WHERE  D.DEPT_NO = E.DEPT_NO

(高效): SELECT  DEPT_NO,DEPT_NAME  FROM  DEPT D  WHERE  EXISTS ( SELECT ‘X'  FROM  EMP E  WHERE E.DEPT_NO = D.DEPT_NO);

6.避免在索引列上使用计算 
    WHERE子句中,如果索引列是函数的一部分.优化器将不使用索引而使用全表扫描.举例: 
    低效: 
      SELECT … FROM  DEPT  WHERE SAL * 12 > 25000; 
    高效: 
      SELECT … FROM DEPT WHERE SAL > 25000/12;
7.用>=替代> 
 高效: 
      SELECT * FROM  EMP  WHERE  DEPTNO >=4 
    低效: 
      SELECT * FROM EMP WHERE DEPTNO >3 
    两者的区别在于, 前者DBMS将直接跳到第一个DEPT等于4的记录而后者将首先定位到DEPTNO=3的记录并且向前扫描到第一个DEPT大于3的记录

 

Insert、update、delete优化

1.避免循环插入、修改、删除

2.也避免超大批量的修改、删除

书写规范

sql语句用大写的;因为oracle总是先解析sql语句,把小写的字母转换成大写的再执行。

其他

1.对查询进行优化,要尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引
2. 对于多张大数据量(这里几百条就算大了)的表JOIN,要先分页再JOIN,否则逻辑读会很高,性能很差
3. count(*)要杜绝
4.如果使用到了临时表,在存储过程的最后务必将所有的临时表显式删除,先 truncate table ,然后 drop table ,这样可以避免系统表的较长时间锁定
5.在新建临时表时,如果一次性插入数据量很大,那么可以使用 select into 代替 create table,避免造成大量 log 
6. 尽量避免使用游标操作大量的数据行

索引

措施

1.  解析SQL语句, 估算索引的利用率
2.  查询优化统计信息,由sql自动创建的,也可以自建

Create Statistics的作用 - 吾非无心 - 博客园 (cnblogs.com)

 

未确认项

1.总是使用索引的第一个列:
  如果索引是建立在多个列上, 只有在它的第一个列(leading column)被where子句引用时,优化器才会选择使用该索引. 这也是一条简单而重要的规则,当仅引用索引的第二个列时,优化器使用了全表扫描而忽略了索引
2.因为索引需要额外的存储空间和处理,那些不必要的索引反而会使查询反应时间变慢.。定期的重构索引是有必要的(有待确认)

SQL Server 索引重建脚本 - 每天进步多一点 - 博客园 (cnblogs.com)

注意事项

1.尽量不要对索引列进行计算、类型改变,否则相当于索引无效

2.尽量不要对索引列使用!= ,not 等,否则相当于索引无效

 

优化目标

sqlserver性能调优中的逻辑读,物理读,预读是什么意思 - Jearay - 博客园 (cnblogs.com)

 

 

有关sql语句优化的更多相关文章

  1. ruby - 如何在 Ruby 中向现有方法定义添加语句 - 2

    我注意到类定义,如果我打开classMyClass,并在不覆盖的情况下添加一些东西我仍然得到了之前定义的原始方法。添加的新语句扩充了现有语句。但是对于方法定义,我仍然想要与类定义相同的行为,但是当我打开defmy_method时似乎,def中的现有语句和end被覆盖了,我需要重写一遍。那么有什么方法可以使方法定义的行为与定义相同,类似于super,但不一定是子类? 最佳答案 我想您正在寻找alias_method:classAalias_method:old_func,:funcdeffuncold_func#similartoca

  2. Hive SQL 五大经典面试题 - 2

    目录第1题连续问题分析:解法:第2题分组问题分析:解法:第3题间隔连续问题分析:解法:第4题打折日期交叉问题分析:解法:第5题同时在线问题分析:解法:第1题连续问题如下数据为蚂蚁森林中用户领取的减少碳排放量iddtlowcarbon10012021-12-1212310022021-12-124510012021-12-134310012021-12-134510012021-12-132310022021-12-144510012021-12-1423010022021-12-154510012021-12-1523.......找出连续3天及以上减少碳排放量在100以上的用户分析:遇到这类

  3. sql - 查询忽略时间戳日期的时间范围 - 2

    我正在尝试查询我的Rails数据库(Postgres)中的购买表,我想查询时间范围。例如,我想知道在所有日期的下午2点到3点之间进行了多少次购买。此表中有一个created_at列,但我不知道如何在不搜索特定日期的情况下完成此操作。我试过:Purchases.where("created_atBETWEEN?and?",Time.now-1.hour,Time.now)但这最终只会搜索今天与那些时间的日期。 最佳答案 您需要使用PostgreSQL'sdate_part/extractfunction从created_at中提取小时

  4. ruby - ruby 乘法语句中星号中断语法前的空格 - 2

    在添加一些空格以使代码更具可读性时(与上面的代码对齐),我遇到了这个:classCdefx42endendm=C.new现在这将给出“错误数量的参数”:m.x*m.x这将给出“语法错误,意外的tSTAR,期待$end”:2/m.x*m.x这里的解析器到底发生了什么?我使用Ruby1.9.2和2.1.5进行了测试。 最佳答案 *用于运算符(42*42)和参数解包(myfun*[42,42])。当你这样做时:m.x*m.x2/m.x*m.xRuby将此解释为参数解包,而不是*运算符(即乘法)。如果您不熟悉它,参数解包(有时也称为“spl

  5. ruby - 有没有办法从 ruby​​ case 语句中访问表达式? - 2

    我想从then子句中访问c​​ase语句表达式,即food="cheese"casefoodwhen"dip"then"carrotsticks"when"cheese"then"#{expr}crackers"else"mayo"end在这种情况下,expr是食物的当前值(value)。在这种情况下,我知道,我可以简单地访问变量food,但是在某些情况下,该值可能无法再访问(array.shift等)。除了将expr移出到局部变量然后访问它之外,是否有直接访问caseexpr值的方法?罗亚附注我知道这个具体示例很简单,只是一个示例场景。 最佳答案

  6. ruby - 在 Ruby 的 if 语句中检查 bash 命令 - 2

    如何在Ruby的if语句中检查bash命令的返回值(true/false)。我想要这样的东西,if("/usr/bin/fswscell>/dev/null2>&1")has_afs="true"elsehas_afs="false"end它会提示以下错误含义,它总是返回true。(irb):5:warning:stringliteralincondition正确的语法是什么?更新:/usr/bin/fswscell寻找afs安装和运行状态。它会抛出这样的字符串,Thisworkstationbelongstocell如果afs没有运行,命令以状态1退出 最

  7. ruby - 变量赋值后的 if 语句 - 有多常见? - 2

    我最近与一位同事讨论了以下Ruby语法:value=ifa==0"foo"elsifa>42"bar"else"fizz"end我个人并没有看到太多这种逻辑,但我的同事指出,这实际上是一种相当普遍的Rubyism。我试着用谷歌搜索这个主题,但没有找到任何文章、页面或SO问题来讨论它,这让我相信这可能是一种非常实际的技术。然而,另一位同事发现语法令人困惑,而是将上面的逻辑写成这样:ifa==0value="foo"elsifa>42value="bar"elsevalue="fizz"end缺点是value=的重复声明和隐式elsenil的丢失,如果我们想使用它的话。这也感觉它与Ruby

  8. ruby - 当你有一个没有参数的 case 语句并且 when 子句是 lambda 时会发生什么? - 2

    这段代码没有像我预期的那样执行:casewhen->{false}then"why?"else"ThisiswhatIexpect"end#=>"why?"这也不是casewhen->(x){false}then"why?"else"ThisiswhatIexpect"end#=>"why?"第一个then子句在两种情况下都被执行,这意味着我提供给when子句的lambda没有被调用。我知道无论when子句的主题是什么,都应该调用大小写相等运算符===。我想知道当没有为case提供参数时,===的另一边会发生什么。我在想它可能是nil,但它不可能是:->{false}===nil#=>

  9. sql - 在 Rails Console for PostgreSQL 的表中显示数据 - 2

    我找到了这样的东西:Rails:Howtolistdatabasetables/objectsusingtheRailsconsole?这一行没问题:ActiveRecord::Base.connection.tables并返回所有表但是ActiveRecord::Base.connection.table_structure("users")产生错误:ActiveRecord::Base.connection.table_structure("projects")我认为table_structure不是Postgres方法。如何列出Postgres数据库的Rails控制台中表中的所有

  10. ruby - 防止SQL注入(inject)/好的Ruby方法 - 2

    Ruby中防止SQL注入(inject)的好方法是什么? 最佳答案 直接使用ruby?使用准备好的语句:require'mysql'db=Mysql.new('localhost','user','password','database')statement=db.prepare"SELECT*FROMtableWHEREfield=?"statement.execute'value'statement.fetchstatement.close 关于ruby-防止SQL注入(inject

随机推荐