oracle 性能优化(二)——如何使用oracle 自带的性能分析工具,进行sql性能优化
第一步:执行会话统计,找到需要优化的sql
--注意:v$sql 与v$sqlarea 有很大的区别就在与,v$sqlarea 是根据sqltext进行分类的,那就会导致不同用户执行了同一个sql,被统计在了一起,所以一定要使用v$sql. ---查询每个进程执行的对应的sql,以及可以干掉该sql的sql语句 --spid oracle 程序进程号 --executions 代表执行次数 --EXACT_MATCHING_SIGNATURE 没有删除常量时,算出来的hash值 --常量就是where后面这些字段等于的值。 --FORCE_MATCHING_SIGNATURE 代表可以共享coursor(即可以实现软件解析)。 删除了常量时,算出来的hash值。 如果SQL中有绑定变量,那就是没有常量,所以force_matching_signature就会与exact_matching_signature一样的生成标准 。所以就可以说是实现了绑定变量。 --version_count 当有大量的version_count,说明虽然SQL语句相同,但是Oracle 发现因为某些原因不可重用这些SQL,此时,再去查看 c.* 中的值,找到为 Y 的列,就是sql不能重用的原因 --cpu_time 和elapsed_time 单位都是ms。 每次执行的时间,需要处理,执行次数 --alterxxxxxx 这个是删除sql的语法 (只能在sql/plus 中执行) ---machine 代表是谁发起的这个sql ---order by 为了根据谁最消耗cpu进行排序 select d.sql_text,d.sql_fulltext,a.spid,a.pid,b.sql_id,d.executions,e.version_count,d.EXACT_MATCHING_SIGNATURE,d.FORCE_MATCHING_SIGNATURE,b.username,b.MACHINE,d.cpu_time,d.ELAPSED_TIME,c.*,b.sid,b.serial#, \'alter system kill session\'\'\'||b.SID||\',\'||b.serial#||\'\'\';\' from v$sql d,v$process a, v$session b,v$sql_shared_cursor c,v$sqlarea e where a.addr = b.paddr and b.SQL_ID=d.SQL_ID and c.sql_id=d.sql_id and e.sql_id=d.sql_id order by d.cpu_time desc
第二步:拿到需要优化的sql,在测试脚本中,运行
-- Created on 2019-03-07 by ADMINISTRATOR declare -- Local variables here my_task_name VARCHAR2(30); begin --更新表的统计信息 --dbms_stats.gather_table_stats(\'pmsuser\',\'PMS_PRODUCT_INFO\',cascade=>true); --执行 my_task_name :=DBMS_SQLTUNE.CREATE_TUNING_TASK( -- sql_id => \'7f34mcwy3506w\', sql_text=> \'select t.id, t.store_name, prov.name storeProv, city.name storeCity, area.name storeArea, t.store_addr storeAddr from pmsuser.pms_firm_store_info t left join pmsuser.sys_area prov on t.STORE_PROV = prov.id left join pmsuser.sys_area city on t.STORE_CITY = city.id left join pmsuser.sys_area area on t.STORE_AREA = area.id where t.status = \'\'100002\'\' and exists (select 1 from pmsuser.pms_r_saler_store a left join pmsuser.pms_r_product_store b on a.str_id = b.obj_id left join pmsuser.pms_product_affiliated_core c on b.version_no = c.version_no left join pmsuser.pms_product_info d on c.product_no = d.product_no where t.id = a.str_id and a.is_del = \'\'100002\'\' and b.status = \'\'100017\'\' and c.is_del = \'\'100017\'\' and d.status = \'\'100017\'\' and a.firm_id = \'\'500007001\'\' and a.user_id = \'\'ZHXJDY0705\'\' and d.product_type = \'\'200001\'\')\', scope => \'COMPREHENSIVE\',time_limit => 60, task_name => \'test_sql_tuning_task2\', description => \'Task to tune a query\'); DBMS_SQLTUNE.EXECUTE_TUNING_TASK(task_name => \'test_sql_tuning_task2\'); /* --查看结果 select dbms_sqltune.report_tuning_task(\\'test_falist_tuning_task1\\') from dual; --删除执行结果 dbms_sqltune.drop_tuning_task(\'test_sql_tuning_task2\'); */ /* --至今未研究明白 my_task_name :=DBMS_ADVISOR.QUICK_TUNE(DBMS_ADVISOR.SQLACCESS_ADVISOR, v_task_name => \'test_sql_tuning_task2\', v_sql_stmt =>\'SELECT ad.PRODUCT_NO, ur.url CHANNEL_URL,ad.VALID_DAYS QR_CODE_DATE, ad.SELF_URL H5_CHANNEL_URL, ad.PLACE_NAME CHANNEL_NAME, ad.BUSI_CREDIT_TYPE TYPE_OF_SERVICE, ad.PLACE_NO CHANNEL_NO, (CASE WHEN f.LIB_DIRECTORY IS NOT NULL THEN f.LIB_DIRECTORY || f.LIB_NAME || \'\'.\'\' || f.LIB_EXT_NAME ELSE NULL END) CHANNEL_LOGO, ad.PRODUCT_REMARK PRODUCT_INTRODUCTION, ad.APPLY_REMARK APPLICATION_DESCRIPTION, ad.SHOW_WEIGHT DISPLAY_WEIGHT, ad.PROPOSER_NUM APPLICATION_NUMBER, ad.PRODUCT_LABEL PRODUCT_TAG FROM PMSUSER.PMS_PRODUCT_AFFILIATED_ADVERTI ad LEFT JOIN ( SELECT PRODUCT_NO, listagg(URL, \'\'|\'\') WITHIN GROUP (ORDER BY PRODUCT_NO) url FROM PMSUSER.PMS_PRODUCT_ADVERTIS_URL GROUP BY PRODUCT_NO ) ur ON ur.PRODUCT_NO = ad.PRODUCT_NO LEFT JOIN PMSUSER.PMS_LIBRARY_INFO f ON f.ID = ad.FILE_ID WHERE 1 = 1\' ); */ -- Test statements here end;
运行结束后,会生成一份报告,直接运行
select dbms_sqltune.report_tuning_task(\\'test_falist_tuning_task1\\') from dual;
就可以得到结果。根据报告中提及到的优化建议。进行优化
第三步:优化建议,就一定是最好的吗。当然不是,为了保证优化的效果。需要对oracle 给出的建议进行一一尝试。
如果遇到复合索引,建议长度为2,那么该那两个进行组合呢?首先,将唯一性最高的列,作为第一个。第二个列怎么确定呢
如下:
SELECT COUNT( PRODUCT_NO || status) ,COUNT( DISTINCT PRODUCT_NO || status) FROM pmsuser.pms_product_info
这类的方式来确定,这个两个值越接近,说明其唯一性就越高,那么这两个值来组合最好。
第四步:当然是验证自己创建的索引的效果
赠送创建/删除索引的语句:
drop index PMSUSER.IDX_rss_userid_isdel; create index PMSUSER.IDX_rss_userid_isdel on PMSUSER.PMS_R_SALER_STORE("USER_ID","FIRM_ID");