当前位置: 首页 > 科技观察

SQL优化技巧总结,及案例分析

时间:2023-03-16 01:20:25 科技观察

判断问题SQL判断SQL是否有问题可以从两个表象来判断:系统层面表示CPU消耗严重IO等待严重页面响应时间过长使用sar命令和top命令查看当前系统状态。也可以通过Prometheus、Grafana等监控工具观察系统状态。SQL语句出现冗长,执行时间过长。全表扫描获取数据。执行计划中的rows和cost都很大,冗长的SQL很容易看懂。如果一条SQL太长,可读性肯定会差,出现问题的频率肯定会更高。进一步判断SQL问题,还得从执行计划入手,如下图:执行计划告诉我们,这个查询进行了全表扫描Type=ALL,而且行数很大(9950400),可以基本上可以判断为“有味道”的SQL。获取问题不同的SQL数据库有不同的获取方式,以下是目前主流数据库的慢查询SQL获取工具MySQL慢查询日志测试工具loadrunnerPercona的ptquery等工具OracleAWR报表测试工具loadrunner等相关内部视图如v$,$GRIDCONTROLsession_wait等监控工具大梦数据库AWR报表测试工具loadrunner等大梦性能监控工具(dem)相关内部视图如v$,$session_wait等SQL编写技巧SQL编写有以下通用技巧:Reasonable索引的使用索引越少,查询就会越慢;索引过多会占用大量空间,而且在执行增删改查语句时需要动态维护索引,影响性能。选择率高(重复值少),被where频繁引用,需要建立B树索引;一般情况下,join列需要建立索引;复杂文档类型查询使用全文索引效率更高;索引的建立要在查询和DML性能之间取得平衡;创建复合索引时,要注意基于非前导列的查询使用UNIONALL而不是UNIONUNIONALL,执行效率高于UNION,UNION在执行时需要对数据进行排序;UNION需要对数据进行排序?执行SQL时避免select*的写法,优化器需要将*转换成特定的列;每次查询都要返回表,不能使用覆盖索引。?建议对JOIN字段进行索引。通常,JOIN字段是预先建立索引的。?避免复杂的SQL语句以提高可读性;避免慢查询的概率;可以转化为多个短查询,由业务方处理?避免where1=1的写法?避免类似RAND()的orderbyrand(),会导致数据列被多次扫描SQL优化执行计划完成后SQL优化,必须先阅读执行计划。执行计划会告诉你哪里效率低,哪里需要优化。下面以MYSQL为例,看看执行计划是怎样的。(每个数据库的执行计划都不一样,需要自己去了解)sql讲解下面我们用一个实际的优化案例来说明SQL的优化过程和优化技巧。优化案例表结构CREATETABLE`a`(`id`int(11)NOTNULLAUTO_INCREMENT,`seller_id`bigint(20)DEFAULTNULL,`seller_name`varchar(100)CHARACTERSETutf8COLLATEutf8_binDEFAULTNULL,`gmt_create`varchar(30)DEFAULTNULL,PRIMARY`KEY());创建表`b`(`id`int(11)NOTNULLAUTO_INCREMENT,`seller_name`varchar(100)DEFAULTNULL,`user_id`varchar(50)DEFAULTNULL,`user_name`varchar(100)DEFAULTNULL,`sales`bigint(20)DEFAULTNULL,`gmt_create`varchar(30)DEFAULTNULL,PRIMARYKEY(`id`));CREATETABLE`c`(`id`int(11)NOTNULLAUTO_INCREMENT,`user_id`varchar(50)DEFAULTNULL,`order_id`varchar(100)DEFAULTNULL,`state`bigint(20)DEFAULTNULL,`gmt_create`varchar(30)DEFAULTNULL,PRIMARYKEY(`id`));三张表关联查询当前用户在当前时间前后10小时的订单状态,按照订单创建时间从小到大的顺序排列,具体SQL如下selecta.seller_id,a.seller_name,b.user_name,c.statefroma,b,cwherea.seller_name=b.seller_nameandb.user_id=c.user_idandc.user_id=17anda.gmt_createBETWEENDATE_ADD(NOW(),INTERVAL–600MINUTE)ANDDATE_ADD(NOW(),INTERVAL600MINUTE)orderbya.gmt_create;检查数据卷的原始执行行时间原执行计划初步优化思路SQL中where条件字段类型要与表结构保持一致。表中user_id为varchar(50)类型,实际SQL中使用的int类型有隐式转换,不加索引将b和c表user_id字段改为int类型。因为b表和c表有关联,所以在b表和c表的user_id上建立索引。因为a表和b表有关联,所以在a表和b表的seller_name字段上建立索引。使用复合索引剔除临时表和排序初步优化SQLaltertablebmodify`user_id`int(10)DEFAULTNULL;altertablecmodify`user_id`int(10)DEFAULTNULL;altertablecaddindex`idx_user_id`(`user_id`);altertablebaddindex`idx_user_id_sell_name`(`user_id`,`seller_name`);altertableaaddindex`idx_sellname_gmt_sellid`(`gmt??_create_`,`seller_id`);查看优化后的执行时间查看优化后的执行计划查看警告信息继续优化altertableamodify"gmt_create"datetimeDEFAULTNULL;查看执行时间查看执行计划摘要查看执行计划说明如果有警告,查看告警信息showwarnings;查看SQL涉及的表结构和索引信息根据执行计划,思考可能的优化点根据可能的优化点进行表结构更改、添加索引、SQL重写等操作查看优化后的执行时间和执行计划if优化效果不明显,重复第四步