导致oracle sql运行速度突然变慢的原因可能有很多。下面列举了一些常见的原因,以及判断和处理的方法。
一. 执行计划改变及处置方法
执行计划的变化通常是由于多种因素相互作用的结果。以下是一些可能导致执行计划变化的原因,以及详细解释:
1. 统计信息变化
oracle优化器依赖统计信息来生成最佳执行计划。当表或索引的统计信息发生变化时(例如,数据量变化、数据分布变化等),优化器可能会为sql选择不同的执行计划。统计信息可能由以下操作更新:手动收集统计信息、自动任务收集统计信息或者导入统计信息。
以下方法检查统计信息是否发生变化
统计信息收集时间
select owner,table_name,tablespace_name,to_char(last_analyzed,'yyyymmdd hh24:mi:ss') from dba_tables where table_name='$table_name';
统计信息是否过期
col subpartition_name for a50
select subpartition_name,owner,table_name,last_analyzed,stale_stats,object_type,partition_name from dba_tab_statistics where owner='$owner' and table_name='$table_name';
2. 数据库参数变更
数据库参数(如,optimizer_mode
、optimizer_index_cost_adj
等)会影响优化器的行为和决策。当这些参数发生变化时,可能会导致执行计划变化。数据库参数可以在会话级别或系统级别进行修改。
3. 对象定义的改变
表、索引或其他数据库对象的定义发生变化时,可能会影响执行计划。例如,添加、删除或修改索引;更改表的存储参数;更改表的分区方案等。
4. sql语句本身的更改
当sql语句本身发生变化(例如,更改谓词条件、更改join顺序等)时,可能会导致执行计划变化。即使是微小的更改,也可能导致优化器选择不同的执行计划。
5. 优化器行为的变化
oracle数据库的不同版本可能具有不同的优化器行为。在升级数据库版本或应用补丁后,优化器可能会选择不同的执行计划。此外,对于带有绑定变量的sql,当绑定变量的值发生变化时,优化器可能会为不同的值选择不同的执行计划(这称为绑定变量窥探)。
- 当优化器解析一个带有绑定变量的sql语句时,它会查看绑定变量的实际值,并根据这些值评估谓词的选择性(selectivity)。
- 优化器根据谓词的选择性生成执行计划。在具有不同数据分布的情况下,不同的绑定变量值可能导致不同的执行计划。
- 对于相同的sql语句,优化器会将生成的执行计划缓存到库存游标(cursor cache)中,以便后续的相同sql语句可以直接使用缓存的执行计划。
- 当绑定变量的值发生变化时,优化器可以根据新值重新评估谓词的选择性,并在必要时生成新的执行计划。这有助于在不同绑定变量值的情况下为sql语句选择最优的执行计划。
尽管绑定变量窥视在许多情况下可以提高带有绑定变量的sql语句的性能,但在某些情况下,它可能导致性能下降。例如,当绑定变量值在不同执行之间具有高度波动性时,优化器可能会为某些值选择次优的执行计划。在这种情况下,可以考虑使用adaptive cursor sharing(acs)或sql plan baselines等技术来解决性能问题。
6. 系统资源可用性变化
当系统资源(例如,cpu、内存、i/o等)发生变化时,可能会影响优化器的决策。例如,当系统负载较高时,优化器可能会倾向于选择较少资源消耗的执行计划。
要诊断和处理执行计划变化,可以采用以下方法:
7、处置方法
1. sql plan baselines
sql plan baselines是一种用于捕获、选择和管理执行计划的技术,以确保sql语句的执行计划稳定性。通过使用sql plan baselines,可以锁定特定的执行计划并防止因执行计划变化而导致性能下降。
- 启用自动捕获sql plan baselines:
要启用自动捕获功能,需要将参数optimizer_capture_sql_plan_baselines
设置为true
。可以通过以下命令来设置:
sql
alter system set optimizer_capture_sql_plan_baselines = true;
- 手动捕获sql plan baselines:
如果不希望自动捕获sql plan baselines,可以手动捕获它们。可以使用dbms_spm
包中的load_plans_from_cursor_cache
或load_plans_from_sqlset
函数来实现这一目的。以下是一个示例:
首先,从sql语句的库存游标(cursor cache)中捕获sql plan baselines:
sql
declare
num_plans_loaded integer;
begin
num_plans_loaded := dbms_spm.load_plans_from_cursor_cache(sql_id => 'your_sql_id');
end;
/
或者,从sql tuning set(sts)中捕获sql plan baselines:
sql
declare
num_plans_loaded integer;
begin
num_plans_loaded := dbms_spm.load_plans_from_sqlset(sqlset_name => 'your_sqlset_name', basic_filter => 'sql_id = "your_sql_id"');
end;
/
一旦创建了sql plan baselines,oracle优化器将尝试在执行sql语句时使用它们。请注意,为了避免性能问题,优化器可能会在运行时选择一个比基线计划更优的执行计划。可以通过dbms_spm
包中的函数来管理和维护sql plan baselines,例如evolve_sql_plan_baseline
、drop_sql_plan_baseline
等。管理sql plan baselines主要涉及到创建、修改、演进、删除和查看它们。以下是一些使用dbms_spm包进行sql plan baselines管理的常用方法:
-
创建sql plan baselines:
如前所述,可以使用load_plans_from_cursor_cache
或load_plans_from_sqlset
函数从库存游标或sql tuning set中捕获sql plan baselines。 -
查看sql plan baselines:
可以通过查询dba_sql_plan_baselines
视图来查看现有的sql plan baselines。
select sql_handle, plan_name, origin, enabled, accepted, fixed
from dba_sql_plan_baselines;
- 演进sql plan baselines:
使用evolve_sql_plan_baseline
函数可以比较当前执行计划与已知的基线计划,确定新计划是否更优。如果新计划更优,它将被添加到执行计划基线中。
declare
l_plans_evolved_count integer;
begin
l_plans_evolved_count := dbms_spm.evolve_sql_plan_baseline(sql_handle => 'your_sql_handle');
end;
/
- 修改sql plan baselines属性:
使用alter_sql_plan_baseline
函数可以修改sql plan baselines的属性,如启用、禁用、接受或固定某个执行计划基线。
begin
dbms_spm.alter_sql_plan_baseline(
sql_handle => 'your_sql_handle',
plan_name => 'your_plan_name',
attribute_name => 'attribute_name',
attribute_value => 'attribute_value'
);
end;
/
- 删除sql plan baselines:
使用drop_sql_plan_baseline
函数可以删除不再需要的sql plan baselines。
begin
dbms_spm.drop_sql_plan_baseline(
sql_handle => 'your_sql_handle',
plan_name => 'your_plan_name'
);
end;
/
- 验证sql plan baselines:
可以使用dbms_spm.test_sql_plan_baseline
函数验证sql plan baselines。这将对基线执行计划执行性能测试,并返回相关的性能数据。例如:
declare
l_result clob;
begin
l_result := dbms_spm.test_sql_plan_baseline(
sql_handle => 'your_sql_handle',
plan_name => 'your_plan_name'
);
dbms_output.put_line(l_result);
end;
/
- 指定验证时间阈值:
可以使用set_evolve_task_parameter
函数设置sql plan baselines演进任务的参数。:
begin
dbms_spm.set_evolve_task_parameter(
task_name => 'your_task_name',
parameter_name => 'time_limit',
parameter_value => 300
);
end;
/
- 创建和执行sql plan baselines演进任务:
使用create_evolve_task
函数创建sql plan baselines演进任务,并使用execute_evolve_task
函数执行任务。
begin
dbms_spm.create_evolve_task(
task_name => 'your_task_name',
sql_handle => 'your_sql_handle'
);
dbms_spm.execute_evolve_task(task_name => 'your_task_name');
end;
/
- 查看任务结果:
使用report_evolve_task
函数生成sql plan baselines演进任务的报告。例如:
declare
l_report clob;
begin
l_report := dbms_spm.report_evolve_task(task_name => 'your_task_name', report_level => 'all');
dbms_output.put_line(l_report);
end;
/
2. sql profiles
sql profiles 是 oracle 为 sql 优化器提供的一种调整机制,它可以影响优化器在生成执行计划时使用的统计信息和优化器参数。sql profiles 可以帮助优化器更准确地估计执行计划的成本,并为性能问题的 sql 语句提供更好的执行计划。以下是如何使用 sql profiles 的步骤:
- 使用 sql tuning advisor(sql 调优顾问):
sql profiles 通常是通过 sql tuning advisor 自动生成的。可以创建调优任务并运行 sql tuning advisor,以查找 sql 语句的潜在性能问题和建议的 sql profiles。例如:
declare
l_task_id varchar2(100);
begin
l_task_id := dbms_sqltune.create_tuning_task(sql_id => 'your_sql_id');
dbms_sqltune.execute_tuning_task(task_name => l_task_id);
end;
/
- 查看调优任务报告:
使用dbms_sqltune.report_tuning_task
函数查看调优任务的报告,以查找建议的 sql profiles。
set long 1000000
set longchunksize 1000000
set linesize 200
set pagesize 200
select dbms_sqltune.report_tuning_task(task_name => 'your_task_id') as report
from dual;
- 接受 sql profiles:
如果调优任务报告中建议了 sql profiles,可以使用dbms_sqltune.accept_sql_profile
函数接受它们。例如:
begin
dbms_sqltune.accept_sql_profile(
task_name => 'your_task_id',
name => 'your_profile_name'
);
end;
/
- 查看和管理 sql profiles:
可以使用以下 sql 查询查看现有的 sql profiles:
select name, sql_text, category, status, created
from dba_sql_profiles;
要删除不再需要的 sql profiles,使用 dbms_sqltune.drop_sql_profile
函数。
begin
dbms_sqltune.drop_sql_profile(name => 'your_profile_name');
end;
/
- 使用 sql plan baselines 和 sql profiles:
在某些情况下,可能需要同时使用 sql plan baselines 和 sql profiles。sql plan baselines 用于确保执行计划的稳定性,而 sql profiles 可以帮助优化器为性能问题的 sql 语句生成更好的执行计划。
当同时使用这两个功能时,优化器首先会在 sql plan baselines 中查找可用的执行计划。如果找到一个合适的执行计划,优化器将使用该计划。如果没有找到合适的执行计划,优化器将尝试应用 sql profiles 生成新的执行计划。这样,可以在保持执行计划稳定性的同时,为具有性能问题的 sql 语句提供更好的执行计划。
- 监控 sql profiles 的影响:
定期监控 sql profiles 对 sql 语句性能的影响。可以通过查询dba_sql_profiles
和v$sql
视图来监控 sql profiles 的使用情况。例如,可以使用以下查询查看受 sql profiles 影响的 sql 语句:
select p.name, s.sql_id, s.sql_text, s.executions, s.elapsed_time, s.cpu_time
from dba_sql_profiles p, v$sql s
where p.sql_id = s.sql_id;
总之,使用 sql profiles 可以帮助优化器更准确地估计执行计划的成本,并为具有性能问题的 sql 语句生成更好的执行计划。同时监控和分析 sql profiles 的使用情况,以确保它们对数据库性能产生积极的影响。在对生产环境进行任何更改之前,请确保在测试环境中验证更改效果,以免对生产环境造成负面影响。
3. 使用sql hint
在某些情况下,可能需要手动干预执行计划的选择。使用sql hint可以为优化器提供额外的信息,从而影响执行计划的选择。例如,可以指定join方法、驱动表等。
sql hints 是一种告诉 oracle 优化器如何执行特定 sql 语句的方法。使用 hints,可以强制优化器采用认为最佳的执行计划。然而,请注意,过度使用 hints 可能会导致不良的性能影响。应始终将 hints 视为最后手段,在考虑其他性能调优方法后使用。以下是一些常用的 sql hints:
- leading:
指定驱动表顺序。例如:
select /* leading(e, d) */ ...
from employees e, departments d
where ...
- use_nl:
指示优化器使用嵌套循环连接。例如:
select /* use_nl(e, d) */ ...
from employees e, departments d
where ...
- use_hash:
指示优化器使用哈希连接。例如:
select /* use_hash(e, d) */ ...
from employees e, departments d
where ...
- use_merge:
指示优化器使用合并连接。例如:
select /* use_merge(e, d) */ ...
from employees e, departments d
where ...
- full:
指示优化器执行全表扫描。例如:
select /* full(e) */ ...
from employees e
where ...
- index:
指示优化器使用特定索引。例如:
select /* index(e emp_index) */ ...
from employees e
where ...
- no_index:
告诉优化器不要使用特定索引。例如:
select /* no_index(e emp_index) */ ...
from employees e
where ...
- parallel:
指示优化器使用并行执行。例如:
select /* parallel(e, 4) */ ...
from employees e
where ...
- push_pred:
推动连接谓词到视图中。例如:
select /* push_pred(v) */ ...
from employees e, (select ... from ...) v
where ...
- star_transformation:
执行星型转换。例如:
select /* star_transformation */ ...
from fact_table, dimension_table
where ...
- merge_aj:
在执行外连接时使用合并外连接。例如:
select /* merge_aj */ ...
from employees e, departments d
where ...
- pq_distribute:
控制并行查询分布。例如:
select /* pq_distribute(employees, hash, hash) */ ...
from employees, departments
where ...
- cardinality:
设置优化器在生成执行计划时预测的某个表或视图的返回行数。例如:
select /* cardinality(e, 100) */ ...
from employees e
where ...
- gather_plan_statistics:
收集生成执行计划的实际运行时统计信息,有助于调试和性能分析。例如:
select /* gather_plan_statistics */ ...
from employees e
where ...
- result_cache:
将查询结果存储在结果缓存中以提高性能。例如:
select /* result_cache */ ...
from employees e
where ...
- cursor_sharing_exact:
强制某个 sql 语句在解析时使用精确的游标共享模式,即使系统默认设置为不同模式。例如:
select /* cursor_sharing_exact */ ...
from employees e
where ...
- first_rows:
指示优化器优先返回查询的前几行,尽快返回查询结果的前几行。例如:
select /* first_rows(10) */ ...
from employees e
where ...
- all_rows:
指示优化器优化整个查询的执行,不考虑返回前几行的速度。例如:
select /* all_rows */ ...
from employees e
where ...
- opt_estimate:
调整优化器对查询的某个部分的成本估算。例如:
select /* opt_estimate(table e, rows=1000) */ ...
from employees e
where ...
- ordered:
指示优化器按 from 子句中列出的顺序连接表。例如:
select /* ordered */ ...
from employees e, departments d
where ...
4. 监控和诊断工具
详使用oracle提供的监控和诊断工具,如automatic workload repository (awr)、active session history (ash)、sql tuning advisor等,可以帮助识别和解决执行计划变化引起的性能问题。
- awr(自动工作负载存储库)报告:
awr 报告包含一段时间内数据库的性能统计信息。可以生成 awr 报告,然后比较报告中的执行计划和统计信息,以发现问题的根源。使用以下命令生成 awr 报告:
@$oracle_home/rdbms/admin/awrrpt.sql
- ash(活动会话历史)报告:
ash 报告提供了数据库活动会话的实时统计信息。使用 ash 报告可以帮助了解 sql 执行计划变化的实时影响。使用以下命令生成 ash 报告:
@$oracle_home/rdbms/admin/ashrpt.sql
- sql monitor 报告:
sql monitor 报告提供了正在运行的 sql 语句的详细执行信息。可以使用 sql monitor 报告来诊断正在执行的 sql 语句的执行计划变化。使用以下命令生成 sql monitor 报告:
@$oracle_home/rdbms/admin/sqlmon.sql
- vsql_plan 和 vsql_plan_statistics_all 视图:
通过查询 vsql_plan 和 vsql_plan_statistics_all 视图,可以查看 sql 语句的执行计划和统计信息。这有助于了解 sql 执行计划的变化。
例如:
select *
from v$sql_plan
where sql_id = 'your_sql_id'
and child_number = your_child_number
order by id;
- 使用 dbms_xplan.display_cursor:
dbms_xplan.display_cursor 函数允许显示特定 sql 语句的执行计划。通过比较不同时间点的执行计划,可以了解执行计划的变化。
例如:
select *
from table(dbms_xplan.display_cursor('your_sql_id', your_child_number));
-
统计信息:
当表或索引的统计信息发生变化时,可能会导致执行计划变化。要查看表和索引的统计信息,可以查询 dba_tab_statistics、dba_tab_col_statistics 和 dba_index_statistics 视图。 -
查看优化器参数变化:
优化器参数的变化可能会影响 sql 执行计划。通过查询 vspparameter 和 vsystem_parameter 视图,可以检查优化器参数的历史和当前设置。
select name, value
from v$system_parameter
where name like 'optimizer%';
- 使用 sql plan management (spm):
sql plan management 可以帮助捕获、选择和保留最优的执行计划。当 sql 语句的执行计划发生变化时,可以使用 spm 来锁定已知的高性能计划,从而防止性能下降。
例如,使用以下命令创建一个 sql plan baseline:
begin
dbms_spm.load_plans_from_cursor_cache(sql_id => 'your_sql_id');
end;
/
- 分析执行计划变化的影响:
为了了解执行计划变化的影响,可以使用 dbms_sqltune.report_sql_monitor 函数生成一个 sql 监视报告。这有助于确定执行计划变化是否对性能产生负面影响。
例如:
select dbms_sqltune.report_sql_monitor(sql_id => 'your_sql_id') as report
from dual;
- 查看对象定义变化:
对象(如表、视图、索引等)的定义变化可能会导致 sql 执行计划变化。要检查对象定义的变化,可以查询 dba_objects 视图,了解对象的最后一个 ddl 时间。
例如:
select object_name, last_ddl_time
from dba_objects
where owner = 'your_schema'
and object_name = 'your_object_name';
5. sql plan management (spm) 评估和演进
sql plan management (spm) 是 oracle 数据库中的一个功能,用于捕获、选择和保留 sql 语句的最佳执行计划。spm 通过 sql plan baseline 保留已知的高性能计划,以防止由于执行计划变化导致的性能下降。下面是如何使用 spm 进行评估和演进的步骤:
- 捕获 sql 计划:
spm 会自动捕获典型的 sql 语句。还可以手动从光标缓存加载执行计划,例如:
begin
dbms_spm.load_plans_from_cursor_cache(sql_id => 'your_sql_id');
end;
/
- 查看 sql plan baseline:
要查看现有的 sql plan baseline,可以查询 dba_sql_plan_baselines 视图。例如:
select sql_handle, plan_name, origin, enabled, accepted, fixed
from dba_sql_plan_baselines;
- 演进 sql plan baseline:
当新的执行计划可用时,可以使用演进过程来评估它们。演进过程会将新计划与现有计划进行比较,并将性能更好的计划添加到 sql plan baseline 中。可以使用 dbms_spm.evolve_sql_plan_baseline 函数进行演进。例如:
declare
l_plans_evolved_count pls_integer;
begin
l_plans_evolved_count := dbms_spm.evolve_sql_plan_baseline(sql_handle => 'your_sql_handle');
dbms_output.put_line('number of plans evolved: ' || l_plans_evolved_count);
end;
/
- 禁用或启用 sql plan baseline:
可以禁用或启用特定的 sql plan baseline,以防止某些执行计划被优化器选择。使用 dbms_spm.alter_sql_plan_baseline 函数进行操作。例如:
begin
dbms_spm.alter_sql_plan_baseline(
sql_handle => 'your_sql_handle',
plan_name => 'your_plan_name',
attribute_name => 'enabled',
attribute_value => 'no'
);
end;
/
- 删除 sql plan baseline:
如果确定某个执行计划不再需要保留,可以使用 dbms_spm.drop_sql_plan_baseline 函数删除它。例如:
begin
dbms_spm.drop_sql_plan_baseline(
sql_handle => 'your_sql_handle',
plan_name => 'your_plan_name'
);
end;
/
- 导入和导出 sql plan baseline:
为了在不同的环境(例如测试和生产)之间共享 sql plan baseline,可以使用 dbms_spm.pack_stgtab_baseline 和 dbms_spm.unpack_stgtab_baseline 函数将计划导出到 stgtab 表中,然后将它们导入到另一个环境。例如:
-- 导出
begin
dbms_spm.pack_stgtab_baseline(
staging_table_name =>'your_staging_table',
staging_schema_owner => 'your_schema'
);
end;
/
-- 导入
begin
dbms_spm.unpack_stgtab_baseline(
staging_table_name => 'your_staging_table',
staging_schema_owner => 'your_schema'
);
end;
/
6. 创建和使用sql patches
sql patches 是一个 oracle 数据库功能,允许对特定的 sql 语句应用优化器提示,而不需要更改 sql 语句的源代码。这在 sql 语句性能存在问题,但无法直接修改源代码时非常有用。
以下是如何创建和使用 sql patches 的步骤:
- 确定要优化的 sql 语句的 sql_id。
可以通过查询 vsql 或 vsqlarea 视图找到 sql_id。例如:
select sql_id, sql_text
from v$sql
where sql_text like '%your_sql_statement%';
- 使用 dbms_sqldiag.create_sql_patch 函数创建 sql patch。
以下示例演示了如何为指定的 sql_id 创建一个 sql patch,其中包含一个优化器提示(在这里是 use_hash,提示优化器使用散列连接):
declare
l_sql_text clob;
begin
select sql_fulltext
into l_sql_text
from v$sql
where sql_id = 'your_sql_id';
dbms_sqldiag.create_sql_patch(
sql_text => l_sql_text,
hint_text => 'use_hash(@@"sel$1" "your_table_alias")',
name => 'your_sql_patch_name'
);
end;
/
- 验证 sql patch 是否应用成功。
可以查询 dba_sql_patches 视图以查看已应用的 sql patch。例如:
select name, sql_text, hint_text, status
from dba_sql_patches;
如果 sql patch 成功应用,应该能在结果中看到它。现在,当再次运行受影响的 sql 语句时,它将使用包含在 sql patch 中的优化器提示。
- 删除 sql patch。
如果发现 sql patch 对性能没有帮助或导致问题,可以使用 dbms_sqldiag.drop_sql_patch 函数删除它。例如:
begin
dbms_sqldiag.drop_sql_patch(name => 'your_sql_patch_name');
end;
/
7. 利用adaptive cursor sharing (acs)
adaptive cursor sharing (acs) 是 oracle 数据库中的一个功能,用于根据 sql 语句的绑定变量值动态选择最佳执行计划。它解决了当多个用户使用不同的绑定变量值执行相同的 sql 语句时可能出现的性能问题。acs 通过评估不同执行计划的性能,为不同的绑定变量值选择最佳计划。
以下是如何利用 adaptive cursor sharing (acs) 的步骤:
- 确保启用 acs。
在 oracle 数据库 11g 及更高版本中,acs 默认启用。可以通过以下 sql 查询来验证是否启用了 acs:
select name, value from v$parameter where name = 'optimizer_adaptive_cursor_sharing';
如果返回的值为 true
,则表示已启用 acs。如果未启用,可以通过以下 sql 语句启用它:
alter system set optimizer_adaptive_cursor_sharing = true;
- 编写具有绑定变量的 sql 语句。
确保在 sql 语句中使用绑定变量,而不是硬编码值。例如,使用:
select * from employees where department_id = :department_id;
而不是:
select * from employees where department_id = 10;
- 监控 acs 的效果。
可以通过查询 v$sql_shared_cursor 视图来监控 acs 如何为相同的 sql 语句使用不同的执行计划。例如:
select child_number, sql_id, plan_hash_value, executions, is_bind_sensitive, is_bind_aware
from v$sql_shared_cursor
where sql_id = 'your_sql_id';
在结果中,is_bind_sensitive
列表示该 sql 语句是否被认为是绑定敏感的,而 is_bind_aware
列表示该 sql 语句是否具有绑定感知的执行计划。如果这两个值都为 y
,则表示 acs 有效地为不同的绑定变量值选择了不同的执行计划。
- 分析和调整。
如果发现 acs 对某些 sql 语句的性能没有帮助,可以通过分析该语句的执行计划、收集相关对象的统计信息或使用 sql plan management (spm) 来进一步优化。
请注意,在某些情况下,acs 可能无法为特定 sql 语句提供理想的性能。在这种情况下,可能需要采用其他性能优化技术,如 sql profiles、sql patches 或改进 sql 语句的编写。在进行任何更改之前,请确保在测试环境中验证更改效果,以免对生产环境造成负面影响。
二. 数据库资源争用
数据库资源争用会导致 sql 执行效率降低。以下是一些可能导致 sql 执行速度变慢的资源争用类型,以及如何判断和处理这些资源争用:
1. 锁争用(lock contention)
select * from v$lock where request > 0;
处理方法:识别和解决导致锁争用的事务,例如通过重新设计应用程序逻辑或调整事务隔离级别。
用于查看阻塞链
@swc sid||':'||serial#||':'||event||':'||username||':'||inst_id||':'||username 1=1
@dash_wait_chains username||':'||':'||session_id||':'||session_serial#||':'||event2||':'||program2||':'||time_model_name||':'||objt session_type='foreground' "timestamp'2023-04-20 00:00:00'" "timestamp'2023-04-21 00:00:00'"
@dash_wait_chains username||':'||':'||session_id||':'||session_serial#||':'||event2||':'||program2||':'||time_model_name session_type='foreground' sysdate-1 sysdate
@ash_wait_chains username||':'||':'||session_id||':'||session_serial#||':'||event2||':'||program2||':'||time_model_name||':'||objt session_type='foreground' "timestamp'2023-04-20 00:00:00'" "timestamp'2023-04-21 00:00:00'"
@ash_wait_chains username||':'||':'||session_id||':'||session_serial#||':'||event2||':'||program2||':'||time_model_name session_type='foreground' sysdate-1 sysdate
2. i/o 争用
要确定是否存在 i/o 争用,可以通过以下方法进行检查:
-
检查系统 i/o 状态:
使用操作系统提供的工具(如 iostat(linux/unix),perfmon(windows))检查磁盘的 i/o 使用情况。关注磁盘队列长度、读写延迟、i/o 吞吐量等指标。如果这些指标超过正常水平,可能存在 i/o 争用。
-
分析 oracle awr 报告:
oracle 的 automatic workload repository (awr) 报告提供了数据库性能的详细分析。在 awr 报告中,关注以下部分:
- 查找 “i/o profile” 和 “instance activity stats” 部分,检查 i/o 相关的等待事件和统计数据,如 “db file sequential read”、“db file scattered read” 等。
- 在 “top timed events” 部分,如果 i/o 相关的等待事件(如 “db file sequential read”、“db file scattered read”、“log file parallel write” 等)占据了较大的等待时间比例,可能存在 i/o 争用。
-
检查 oracle 等待事件:
可以查询
v$system_event
和v$session_event
视图,分析 i/o 相关的等待事件。例如:select event, total_waits, time_waited from v$system_event where event like 'db file%';
如果 i/o 相关事件的等待时间较长,可能存在 i/o 争用。
-
检查 oracle 的 i/o 压力:
可以通过查询
v$filestat
和v$tempstat
视图检查数据文件和临时文件的 i/o 情况。例如:select file#, phyrds, phywrts, readtim, writetim from v$filestat;
关注具有较高 i/o 操作或 i/o 时间的文件,分析是否存在 i/o 争用。
如何处理 i/o 争用:
- 优化 sql 语句以减少 i/o 请求,例如通过添加索引、重新编写查询或分区表等方法。
- 考虑使用更快的硬件,例如 ssd 或更快的磁盘阵列。
- 调整数据库文件布局,将热数据文件放在不同的磁盘上,以减轻 i/o 争用。
- 考虑使用 oracle 功能,如 automatic storage management (asm) 或 direct nfs (dnfs),以更好地管理 i/o 负载。
- 调整 oracle 参数,例如增加 sga 大小,以减少对磁盘 i/o 的依赖。
3. cpu 争用
要确定是否存在 cpu 争用导致 sql 执行效率变慢,可以通过以下方法进行检查:
-
检查系统 cpu 使用率:
使用操作系统提供的工具(如 top(linux/unix),task manager(windows))检查系统的 cpu 使用情况。如果系统的 cpu 使用率持续较高,可能存在 cpu 争用。
-
分析 oracle awr 报告:
oracle 的 automatic workload repository (awr) 报告提供了数据库性能的详细分析。在 awr 报告中,关注以下部分:
- 查找 “top timed events” 部分,如果 cpu 相关的等待事件(如 “cpu time”)占据了较大的等待时间比例,可能存在 cpu 争用。
- 在 “os statistics” 部分,检查 “%busy” 和 “%user” 等指标,如果这些指标持续较高,可能存在 cpu 争用。
-
检查 oracle 等待事件:
可以查询
v$system_event
和v$session_event
视图,分析 cpu 相关的等待事件。例如:select event, total_waits, time_waited from v$system_event where event = 'cpu time';
如果 cpu 时间占据了较大比例的等待时间,可能存在 cpu 争用。
-
检查 oracle 的系统统计信息:
查询
v$sys_time_model
和v$osstat
视图,分析 cpu 使用情况。例如:select stat_name, value from v$sys_time_model where stat_name in ('db time', 'db cpu'); select stat_name, value from v$osstat where stat_name like 'busy%';
关注较高的 cpu 使用率和系统负载,分析是否存在 cpu 争用。
如何处理 cpu 争用:
- 优化 sql 语句以减少 cpu 负载,例如通过重写查询、添加索引或使用更有效的聚合函数等方法。
- 考虑在必要时升级硬件以增加 cpu 资源。
- 调整 oracle 参数,例如调整 pga_aggregate_target、cpu_count 或 parallel_max_servers 等,以更好地管理 cpu 资源。
- 调整应用程序逻辑,例如通过减少事务冲突或并发请求数,以降低 cpu 负载。
- 对于并行查询,可以调整并行度,以充分利用 cpu 资源或减轻 cpu 争用。
4. 前后台进程争用:
当前台进程(例如用户会话)和后台进程(例如日志写入进程)争用资源时,可能会导致 sql 执行速度变慢。要判断前后台进程争用导致 sql 执行效率变慢,可以通过以下方法进行检查:
-
分析 oracle awr 报告:
oracle 的 automatic workload repository (awr) 报告提供了数据库性能的详细分析。在 awr 报告中,关注以下部分:
- 查找 “top timed events” 部分,如果与前后台进程相关的等待事件(如 “latch: shared pool”、“log file sync”、“log buffer space” 等)占据了较大的等待时间比例,可能存在前后台进程争用。
- 在 “foreground wait events” 和 “background wait events” 部分,检查与前后台进程相关的等待事件,以了解是否存在争用。
-
检查 oracle 等待事件:
可以查询
v$system_event
和v$session_event
视图,分析与前后台进程相关的等待事件。例如:select event, total_waits, time_waited from v$system_event where event in ('latch: shared pool', 'log file sync', 'log buffer space');
如果与前后台进程相关的等待事件具有较长的等待时间,可能存在进程争用。
-
检查 oracle 会话和进程:
查询
v$session
和v$process
视图,了解前后台进程的状态和活动。例如:select s.sid, s.serial#, s.username, s.program, s.status, p.spid, p.bg_flag from v$session s join v$process p on s.paddr = p.addr;
关注阻塞会话或具有较高资源消耗的进程,以了解是否存在前后台进程争用。
如何处理前后台进程争用:
-
优化 sql 语句以减少资源消耗,例如通过重写查询、添加索引或使用更有效的聚合函数等方法。
-
调整 oracle 参数,例如调整 log_buffer、log_checkpoints_to_alert 或 shared_pool_size 等,以减轻前后台进程争用。
-
对于与日志写入相关的争用,可以考虑使用更快的磁盘或配置多个日志组。
-
识别并优化具有较高资源消耗的应用程序逻辑,以降低前后台进程争用。
-
对于并行查询,可以调整并行度,以充分利用资源或减轻前后台进程争用。
select * from v$session_wait where event like 'latch:%';
处理方法:调整相关参数,以平衡前后台进程之间的资源分配。
-
缓冲区争用:
当多个会话试图访问或修改同一缓冲区时,可能会导致缓冲区争用。要判断缓冲区争用导致 sql 执行效率低下,可以通过以下方法进行检查: -
分析 oracle awr 报告:
oracle 的 automatic workload repository (awr) 报告提供了数据库性能的详细分析。在 awr 报告中,关注以下部分:
- 查找 “top timed events” 部分,如果与缓冲区相关的等待事件(如 “buffer busy waits”、“gc buffer busy” 等)占据了较大的等待时间比例,可能存在缓冲区争用。
- 在 “instance activity stats” 部分,检查与缓冲区相关的性能指标(如 “db block gets”、“consistent gets” 等),以了解是否存在缓冲区争用。
-
检查 oracle 等待事件:
可以查询
v$system_event
和v$session_event
视图,分析与缓冲区相关的等待事件。例如:select event, total_waits, time_waited from v$system_event where event in ('buffer busy waits', 'gc buffer busy');
如果与缓冲区相关的等待事件具有较长的等待时间,可能存在缓冲区争用。
-
查询 oracle 的数据文件 i/o:
可以查询
v$filestat
和v$tempstat
视图,了解数据文件和临时文件的 i/o 活动。例如:select file#, phyrds, phywrts, readtim, writetim from v$filestat; select file#, phyrds, phywrts, readtim, writetim from v$tempstat;
关注具有较高 i/o 活动的文件,以了解是否存在缓冲区争用。
如何处理缓冲区争用:
- 优化 sql 语句以减少缓冲区争用,例如通过重写查询、添加索引或使用更有效的聚合函数等方法。
- 调整 oracle 参数,例如调整 db_cache_size 或 db_block_buffers 等,以增加缓冲区资源。
- 对于并行查询,可以调整并行度,以充分利用缓冲区资源或减轻缓冲区争用。
- 对于磁盘 i/o 性能较差的情况,可以考虑使用更快的磁盘或配置 i/o 子系统。
- 对于表分区不均衡导致的缓冲区争用,可以考虑重新分区表以实现更均衡的数据访问。
- 考虑使用 oracle 的自动段空间管理 (assm) 特性,以减少缓冲区争用。
三. 数据和索引碎片
数据和索引碎片会导致 sql 执行效率变慢,主要原因是碎片会导致 i/o 操作增加和访问数据所需的时间增加。
- 碎片可能导致表扫描速度变慢,因为需要读取更多的数据块来获取所需的数据。
- 碎片可能导致索引扫描速度变慢,因为需要遍历更多的索引层次结构以找到相关的数据行。
- 碎片可能导致数据块的使用效率降低,增加缓冲区缓存中的竞争,从而影响整个数据库的性能。
如何判断数据和索引碎片:
-
使用 dbms_space 包中的段空间管理过程来评估表和索引的碎片状况。例如:
declare l_free_blocks number; l_free_bytes number; l_largest_free_blk number; l_unused_blocks number; l_unused_bytes number; l_last_used_extent number; begin dbms_space.unused_space ( segment_owner => 'schema_name', segment_name => 'table_name', segment_type => 'table', free_blocks => l_free_blocks, free_bytes => l_free_bytes, largest_free_blk=> l_largest_free_blk, unused_blocks => l_unused_blocks, unused_bytes => l_unused_bytes, last_used_extent=> l_last_used_extent ); end; /
如果
l_unused_blocks
、l_unused_bytes
或l_largest_free_blk
的值较高,表明可能存在数据碎片。 -
查询
dba_tables
和dba_indexes
视图,查看表和索引的空间使用情况。例如:select table_name, num_rows, blocks, empty_blocks, avg_space, chain_cnt from dba_tables where owner = 'schema_name'; select index_name, blevel, leaf_blocks, distinct_keys, avg_leaf_blocks_per_key, avg_data_blocks_per_key from dba_indexes where owner = 'schema_name';
关注具有高
empty_blocks
、chain_cnt
或高blevel
、低avg_leaf_blocks_per_key
和avg_data_blocks_per_key
值的表和索引,可能存在碎片问题。
如何处理数据和索引碎片:
-
对于表碎片,可以使用以下方法:
- 使用
alter table table_name move
语句重新组织表。 - 使用
dbms_redefinition
包在线重新定义表。 - 使用数据泵工具 (data pump) 进行数据导出和导入。
- 使用
-
对于索引碎片,可以使用以下方法:
- 使用
alter index index_name rebuild
语句重新建立索引。 - 使用
alter index index_name coalesce
语句合并相邻的空闲空间。 - 使用
dbms_space.shrink_space
过程收缩索引空间。例如:
begin dbms_space.shrink_space( segment_owner => 'schema_name', segment_name => 'index_name', segment_type => 'index', compact_segments => true ); end; /
- 使用
-
优化表和索引设计:
- 定期删除无用的数据以减少碎片产生。
- 使用合适的存储参数,如 pctfree、pctused 和 initrans,以减少碎片产生。
- 对于表,可以考虑使用表分区以实现更好的数据管理和降低碎片产生。
- 使用合适的索引类型,如 b-tree 索引、位图索引或函数基索引等,以满足查询需求。
-
监控和维护数据库:
- 定期生成 awr 报告以监控数据库性能,并关注与碎片相关的性能指标。
- 使用 oracle enterprise manager (oem) 或其他数据库管理工具监控和管理碎片。
- 定期进行表和索引的碎片检查和维护,以保持数据库性能稳定。
请注意,不是所有的碎片都会对性能产生负面影响。在进行处理前,请确保已经通过分析和诊断确定碎片确实是性能问题的原因。
-- 检查表碎片
select table_name, round((blocks*8),2) "size (kb)", extents, round((blocks*8)/extents,2) "avg_extent_size (kb)"
from user_tables
where (blocks*8)/extents < ;
-- 检查索引碎片
select index_name, round((leaf_blocks*8),2) "size (kb)", extents, round((leaf_blocks*8)/extents,2) "avg_extent_size (kb)"
from user_indexes
where (leaf_blocks*8)/extents < ;
四. sql语句本身问题
sql 语句本身问题导致 sql 变慢的原因有很多,以下是一些常见的原因及如何判断:
-
低效的查询编写:
- 使用子查询替代连接查询,或者使用笛卡尔积连接。
- 使用嵌套循环查询,而不是使用连接或集合运算。
- 使用 not in、not exists 而不是使用反向连接或外连接。
检查 sql 语句的编写,看是否存在上述情况。如果有,尝试优化并比较执行计划和性能。
-
未使用索引:
- sql 查询没有利用现有的索引。
- 索引列上使用了函数或表达式。
- 查询谓词中的条件不允许使用索引。
查看执行计划,检查是否使用了索引访问路径。如果没有使用索引,分析查询谓词以查找可能的原因。
-
统计信息过时或不准确:
- 数据库统计信息未及时更新。
- 统计信息不准确,导致优化器选择了错误的执行计划。
检查数据表和索引的统计信息,如最后一次收集时间、数据行数、区分度等。如果统计信息过时或不准确,请使用 dbms_stats 包收集新的统计信息。
-
多表连接顺序不当:
- 多表连接顺序不合适,导致执行计划效率低下。
- oracle 优化器没有正确地确定连接顺序。
查看执行计划,检查连接顺序。尝试使用 sql hints(例如 leading、ordered 等)来优化连接顺序,并比较执行计划和性能。
-
数据倾斜:
- 数据分布不均匀,导致查询某些部分数据时性能较差。
- 优化器基于总体统计信息选择了错误的执行计划。
查看数据分布情况。使用 dbms_stats 包收集扩展统计信息,如直方图,以帮助优化器更准确地选择执行计划。
-
会话和系统级参数设置不当:
- 排序区大小不足,导致磁盘排序。
- 优化器参数设置不当,如 optimizer_mode、optimizer_index_cost_adj 等。
检查会话和系统级参数设置,如 sort_area_size、pga_aggregate_target、优化器相关参数等。尝试调整参数并观察性能变化。
要判断 sql 语句本身问题导致 sql 变慢的原因,通常需要查看执行计划、统计信息、参数设置等方面的信息。可以使用oracle 提供的工具(如 explain plan、sql*plus、sql developer、oracle enterprise manager 等)和诊断报告(如 awr、ash、addm 等)来获取相关信息。根据这些信息,可以采取以下措施来优化 sql 语句:
-
重写 sql 查询:
- 尝试使用连接查询替代子查询,或者将笛卡尔积连接替换为有效的连接条件。
- 使用更高效的集合运算替代嵌套循环查询。
- 使用 exists 或反向外连接替代 not in 和 not exists。
-
索引优化:
- 创建合适的索引以提高查询性能。
- 去除索引列上的函数或表达式,以便优化器可以使用索引。
- 调整查询条件以充分利用现有索引。
-
更新统计信息:
- 使用 dbms_stats 包定期收集表和索引的统计信息。
- 收集扩展统计信息,如直方图,以解决数据倾斜问题。
-
优化连接顺序:
- 尝试使用 sql hints(例如 leading、ordered 等)来优化连接顺序。
- 比较不同连接顺序下的执行计划和性能,选择最优的执行计划。
- 调整会话和系统级参数:
- 根据实际需求调整排序区大小、pga_aggregate_target 等参数。
- 调整优化器参数(如 optimizer_mode、optimizer_index_cost_adj 等)以改善执行计划选择。
- 利用 oracle 优化器功能:
- 使用 sql plan management (spm) 来捕获、选择和演进执行计划。
- 使用 sql profiles 和 sql patches 来调整特定 sql 语句的优化器行为。
- 利用 adaptive cursor sharing (acs) 和 adaptive execution plans (aep) 功能以适应不同的数据分布和查询需求。
13.使用10046和10053追踪会话
oracle 提供了事件 10046 和 10053,分别用于跟踪 sql 语句的执行情况和优化器决策过程。这两个事件可以帮助我们更深入地分析 sql 执行效率低下的原因。
- 使用事件 10046 跟踪 sql 执行情况:
事件 10046 用于生成详细的 sql 运行时跟踪信息,包括等待事件、解析、执行和获取等过程。首先,需要设置跟踪级别。跟踪级别从 1 到 12,数字越大,收集的信息越详细。常用的级别有 1(基本统计信息)、4(绑定变量信息)和 8(等待事件信息)。
执行以下步骤以启用 10046 事件跟踪:
a. 登录 sql*plus 并连接到数据库。
b. 执行以下命令以启用跟踪:
alter session set events '10046 trace name context forever, level 12';
c. 运行需要跟踪的 sql 语句。
d. 执行以下命令以停止跟踪:
alter session set events '10046 trace name context off';
e. 在用户跟踪文件目录(user_dump_dest)中找到生成的跟踪文件。文件名通常以 “ora” 开头,扩展名为 “.trc”。
分析跟踪文件可以找到 sql 执行效率低下的原因,如 i/o 等待、cpu 使用、执行计划选择等。可以使用 tkprof 工具将跟踪文件转换为更易读的格式。
- 使用事件 10053 跟踪优化器决策过程:
事件 10053 生成优化器决策过程的详细跟踪信息。它记录了优化器在生成执行计划时所考虑的各种因素和步骤。要启用 10053 事件跟踪,执行以下步骤:
a. 登录 sql*plus 并连接到数据库。
b. 执行以下命令以启用跟踪:
alter session set events '10053 trace name context forever, level 1';
c. 运行需要跟踪的 sql 语句。
d. 执行以下命令以停止跟踪:
alter session set events '10053 trace name context off';
e. 在用户跟踪文件目录(user_dump_dest)中找到生成的跟踪文件。文件名通常以 “ora” 开头,扩展名为 “.trc”。
分析 10053 跟踪文件可以帮助我们了解优化器如何生成执行计划,包括表连接顺序、索引使用、优化器参数等。这有助于我们找到 sql 执行效率低下的原因,例如执行计划选择不佳、索引未被使用等。针对这些问题,我们可以采取相应的优化措施,如重写 sql 语句、创建或调整索引、调整优化器参数等。
在分析 10046 和 10053 跟踪文件时,请注意以下几点:
a. 阅读跟踪文件需要一定的经验和对 oracle 数据库的深入了解。可以借助 oracle 提供的 tkprof 和 trcanlzr 工具以及第三方工具(如 trace analyzer、method r 等)来辅助分析。
b. 跟踪文件可能非常大,特别是在收集详细信息时。在分析跟踪文件时,要关注关键部分,如等待事件、执行计划、优化器估算等。
c. 在生产环境中使用跟踪事件时要谨慎,因为它可能对系统性能产生影响。建议在测试环境中重现问题并进行跟踪分析。
d. 分析跟踪文件后,针对性地优化 sql 语句。注意,在对一个问题进行优化时,可能会引入另一个问题。因此,在每次更改后都要进行全面的测试以确保性能得到提升。
通过对 10046 和 10053 跟踪文件的分析,我们可以更深入地了解 sql 执行效率低下的原因,并采取相应的优化措施。这需要数据库管理员具备一定的经验和技能,以便在复杂的场景下找到性能瓶颈并解决问题。
要在其他会话中启用 10046 和 10053 事件跟踪,请遵循以下步骤:
- 确定目标会话的 sid 和 serial#:
首先,需要获取目标会话的 sid 和 serial#。可以通过查询 v$session 视图来获得这些信息。例如,假设要追踪用户名为 “scott” 的会话,可以使用以下查询:
select sid, serial#, username, status
from v$session
where username = 'scott';
记下查询结果中的 sid 和 serial#,在接下来的步骤中将用到它们。
- 使用 dbms_system 包启用 10046 和 10053 事件跟踪:
在已连接到数据库的 sql*plus 会话中,使用 dbms_system.set_ev 过程启用事件跟踪。将以下命令中的
和
替换为实际的 sid 和 serial# 值:
exec dbms_system.set_ev(
, #>, 10046, 12, ''); -- 启用 10046 事件跟踪,级别为 12 exec dbms_system.set_ev( , #>, 10053, 1, ''); -- 启用 10053 事件跟踪,级别为 1
- 等待目标会话执行 sql 语句:
在此阶段,目标会话的 sql 语句执行将被跟踪。根据事件级别,跟踪文件将包含执行计划、等待事件、绑定变量等详细信息。
- 关闭事件跟踪:
在跟踪完成后,使用 dbms_system.cancel_ev 过程关闭事件跟踪。将以下命令中的
和
替换为实际的 sid 和 serial# 值:
exec dbms_system.cancel_ev(
, #>, 10046); -- 关闭 10046 事件跟踪 exec dbms_system.cancel_ev( , #>, 10053); -- 关闭 10053 事件跟踪
- 分析跟踪文件:
跟踪文件通常位于数据库的 user_dump_dest 目录下,文件名以 “ora” 开头,扩展名为 “.trc”。使用 tkprof 工具或其他第三方工具将跟踪文件转换为易于阅读的格式,然后分析该文件以找出 sql 执行效率低下的原因。
请注意,在生产环境中启用跟踪事件可能对性能产生影响。建议在测试环境中重现问题并进行跟踪分析。
tkprof 是一个 oracle 提供的命令行工具,用于将 10046 跟踪文件转换成更易于阅读和分析的格式。以下是使用 tkprof 分析 10046 跟踪文件的步骤:
a. 定位跟踪文件:
找到包含 10046 跟踪信息的文件。跟踪文件通常位于数据库的 user_dump_dest 目录下,文件名以 “ora” 开头,扩展名为 “.trc”。
b. 使用 tkprof 分析跟踪文件:
在操作系统命令提示符下,使用以下命令运行 tkprof。将
替换为实际的跟踪文件名,将
替换为要生成的输出文件名。
tkprof
[options]
其中,[options]
是 tkprof 支持的一些可选参数,例如:
explain=
:使用指定的用户和密码解释 sql 语句的执行计划。/ sort=
:根据指定的选项对 sql 语句进行排序。可用选项包括:prsela、prsepu、execpu、exerow、exeela、fchela、fchrow 等。sys=yes
:在输出文件中包含系统调用的信息。table=
:将 sql 语句的统计信息插入到指定的表中。
例如,以下命令将跟踪文件 “my_trace_file.trc” 分析为 “my_output_file.txt”,并使用 “scott/tiger” 用户的凭据解释执行计划,同时按照执行时间排序:
tkprof my_trace_file.trc my_output_file.txt explain=scott/tiger sort=exeela
b. 分析输出文件:
tkprof 生成的输出文件包含 sql 语句的执行统计信息,如 cpu 时间、等待事件、执行计划等。阅读输出文件,找出潜在的性能问题并采取相应的优化措施。
请注意,tkprof 的输出文件通常包含大量信息,需要具备一定的数据库知识和经验才能有效地分析和解释这些信息。在分析跟踪文件时,关注关键部分,如等待事件、执行计划、优化器估算等。根据分析结果,可以针对性地优化 sql 语句,例如重写 sql 语句、创建或调整索引、调整优化器参数等。
五. 数据库参数变更
oracle 数据库中的一些参数变更可能会导致 sql 执行效率发生变化。以下是一些可能影响 sql 执行效率的数据库参数:
-
optimizer_mode:优化器模式会影响 sql 语句的执行计划。可选值包括:all_rows(默认值,以最小资源消耗优化)、first_rows(以最快返回前几行为优化目标)、first_rows_n(以最快返回前 n 行为优化目标,其中 n 可为 1、10、100 或 1000)。
-
optimizer_index_cost_adj:该参数用于调整索引访问的成本。较低的值会让优化器更倾向于使用索引访问。范围为 1 到 10000, 默认值为 100。
-
optimizer_index_caching:表示可用于缓存的索引块的百分比。较高的值会让优化器更倾向于使用索引访问。范围为 0 到 100, 默认值为 0。
-
db_file_multiblock_read_count:此参数表示多块读取操作一次读取的最大块数。较高的值会提高全表扫描和索引快速全扫描的效率,但可能会影响其他类型的访问。
-
cursor_sharing:该参数控制 sql 语句绑定变量的替换策略。可选值包括:exact(默认值,不替换绑定变量)、force(强制替换绑定变量,可能导致执行计划变化)、similar(在保证语义一致的情况下替换绑定变量,可能导致执行计划变化)。
-
pga_aggregate_target:指定进程的 pga 工作区总大小。较小的值可能会导致大量磁盘排序和哈希操作,从而降低 sql 执行效率。
-
sga_target 和 sga_max_size:这些参数控制系统全局区(sga)的大小。sga 较小可能会导致缓冲区缓存不足,增加磁盘 i/o 和库缓存争用。
-
_optimizer_adaptive_reporting_only:在 12c 版本中,该隐藏参数控制优化器自适应特性的启用。将此参数设置为 true 可关闭自适应特性,从而影响执行计划。
-
sort_area_size:此参数用于设置用户会话的内存排序区域大小。较小的值可能会导致在磁盘上执行排序,从而降低 sql 执行效率。
-
hash_area_size:此参数用于设置用户会话的哈希聚合操作的内存区域大小。较小的值可能会导致在磁盘上执行哈希操作,从而降低 sql 执行效率。
-
bitmap_merge_area_size:此参数用于设置位图合并操作的内存区域大小。较小的值可能会导致位图合并操作性能较差。
-
star_transformation_enabled:此参数控制星型转换优化功能的启用。设置为 true 时,优化器将尝试使用星型转换优化星型查询,从而可能改变 sql 执行计划。
-
parallel_degree_policy:此参数控制并行度策略。可选值包括:manual(手动,默认值)、auto(自动并行度)、limited(受限并行度)、adaptive(自适应并行度)。更改此参数可能会影响并行执行的策略,进而影响 sql 执行效率。
-
parallel_min_time_threshold:此参数用于设置自动并行执行的时间阈值。当执行计划的时间估计超过该阈值时,优化器将尝试并行执行。
-
result_cache_mode:此参数控制结果缓存模式。可选值包括:manual(手动,默认值)和 force(强制)。更改此参数可能会影响结果缓存的使用情况,进而影响 sql 执行效率。
在调整这些参数之前,请务必充分了解它们的含义和可能的影响。建议在测试环境中验证参数更改对 sql 执行效率的影响。在生产环境中,务必谨慎更改参数,并始终遵循 oracle 支持的最佳实践。
六. 系统资源限制
系统资源限制可能导致 sql 执行效率降低。以下是一些方法,用于判断系统资源限制是否导致 sql 执行效率低下:
-
检查 cpu 使用率:查看操作系统的性能监视器或使用数据库内置的工具(如 awr 报告)检查 cpu 使用率。如果 cpu 使用率持续处于较高水平(如超过 80%),可能存在 cpu 资源争用问题。
-
检查内存使用:检查操作系统的性能监视器或使用数据库内置的工具(如 awr 报告)检查内存使用情况。如果内存使用率持续较高,可能存在内存资源争用问题。此外,查看数据库中 pga 和 sga 的配置和使用情况,以确定是否存在内存分配不足的情况。
-
检查 i/o 性能:使用操作系统工具(如 iostat、sar 等)或数据库内置工具(如 awr 报告、addm 报告等)检查磁盘 i/o 情况。关注 i/o 等待时间、磁盘队列长度等指标,以确定是否存在 i/o 争用问题。
-
查看数据库等待事件:分析数据库等待事件(如 awr 报告中的 top 5 等待事件),确定 sql 执行中是否存在资源争用问题。例如,‘db file sequential read’ 等待事件可能表示存在 i/o 争用,而 ‘latch: shared pool’ 等待事件可能表示存在共享池争用。
-
检查并发会话和并行度:检查数据库中活跃会话的数量,以及并行执行的操作。过多的并发会话和过高的并行度可能导致系统资源争用,从而降低 sql 执行效率。
-
分析操作系统资源限制:查看操作系统的资源限制配置(如 ulimit、kernel 参数等),以确定是否存在操作系统资源限制导致的 sql 执行效率问题。
-
分析数据库资源配置:检查数据库资源配置,如数据库参数、资源计划、资源消耗组等,确定是否存在数据库资源限制导致的 sql 执行效率问题。
通过以上方法,可以初步判断系统资源限制是否导致 sql 执行效率低下。如果确定存在资源限制问题,可以根据具体情况调整系统和数据库配置,以提高 sql 执行效率。
七. 网络延迟
网络延迟可能导致 sql 执行效率降低,特别是在客户端和数据库服务器之间的网络通信中。以下是一些方法,用于判断网络延迟是否导致 sql 执行效率低下:
-
ping 命令:使用 ping 命令测试客户端和数据库服务器之间的网络延迟。例如,输入
ping <数据库服务器ip或主机名>
。观察返回的平均往返时间 (rtt)。如果 rtt 值较高,可能存在网络延迟问题。请注意,这仅能提供初步判断,并不能确切地确定网络延迟是否导致 sql 执行效率低下。 -
traceroute 或 tracert 命令:使用 traceroute(linux 系统)或 tracert(windows 系统)命令来查看客户端和数据库服务器之间的网络路径。例如,输入
traceroute <数据库服务器ip或主机名>
(linux)或tracert <数据库服务器ip或主机名>
(windows)。这将显示数据包在网络中经过的路由节点及其延迟。检查各个节点之间的延迟,以确定是否存在网络延迟问题。 -
分析 sqlnet 等待事件:在 oracle 数据库中,通过查看 awr 报告或使用诸如 enterprise manager 的工具,分析 sqlnet 等待事件(例如 ‘sqlnet message from client’ 和 'sqlnet message to client’)。这些事件表示客户端和服务器之间的网络通信时间。如果这些事件的等待时间较长,可能存在网络延迟问题。
-
使用 oracle 提供的网络诊断工具:oracle 提供了一个名为 tnsping 的工具,可以用于测试 tns 监听器的可达性和响应时间。输入
tnsping
,观察返回的响应时间。如果响应时间较长,可能存在网络延迟问题。 -
分析应用程序日志:检查应用程序日志中是否有关于网络延迟的记录。例如,如果应用程序使用了 oracle jdbc 驱动程序,可以通过设置日志级别来收集 jdbc 连接和执行的详细信息。这可以帮助确定网络延迟是否影响 sql 执行效率。
通过以上方法,可以初步判断网络延迟是否导致 sql 执行效率低下。如果确定存在网络延迟问题,可以与网络管理员协作,以诊断和解决网络相关问题。
如果你已经确定存在网络延迟问题,并且已经与网络管理员进行了协作,以下是一些建议和方法,用于优化网络性能和提高 sql 执行效率:
-
调整会话数据包大小:通过调整客户端和数据库服务器之间的会话数据包大小,可以减少网络传输中的开销。在 oracle 数据库中,可以设置 sql*net 参数 sdu (session data unit) 和 tdu (transport data unit) 来调整数据包大小。
-
使用连接池:为了减少网络延迟对 sql 执行效率的影响,可以使用连接池来重用数据库连接。这将减少建立新连接所需的时间,从而降低网络延迟带来的影响。
-
优化 sql 语句:减少返回的数据量和减少不必要的数据传输。例如,只检索所需的列,使用分页查询以减少每次请求的数据量,使用 exists 而不是 in 子查询等。
-
使用批处理操作:对于大量数据的插入、更新和删除操作,使用批处理操作来减少网络往返次数。
-
考虑使用数据压缩:在客户端和服务器之间传输数据时,使用压缩技术可以减少网络传输的数据量,从而降低网络延迟带来的影响。
-
优化网络基础设施:与网络管理员合作,检查并优化网络设备(如路由器、交换机等)的配置,以降低网络延迟。
-
优化应用程序逻辑:评估和优化应用程序逻辑,以减少对数据库的访问次数和频率。例如,考虑将部分逻辑移至数据库层,通过存储过程、函数或触发器实现,以减少网络通信。
通过以上方法和建议,可以进一步优化网络性能,降低网络延迟对 sql 执行效率的影响。请注意,针对特定环境的优化方法可能有所不同,因此在实施任何更改之前,请确保充分了解它们的潜在影响。
八. 数据库阻塞
数据库阻塞通常是由于一个或多个会话等待其他会话持有的锁或资源而导致的。以下是一些方法和步骤,用于判断数据库阻塞是否导致 sql 执行效率低下:
-
查看数据库等待事件:在 oracle 数据库中,可以通过查看 awr 报告、ash 报告或使用 enterprise manager 等工具来分析数据库等待事件。如果发现锁等待事件(如 ‘enq: tx - row lock contention’、‘enq: hw - contention’ 等)占比较高,可能存在数据库阻塞问题。
-
使用 vsession 和 vlock 视图:在 sql*plus 或其他 sql 工具中,查询 vsession 和 vlock 视图,找出正在等待锁的会话。以下是一个查询示例:
select s.sid, s.serial#, s.username, s.status, s.wait_class, s.seconds_in_wait, l.type, l.lmode, l.request from v$session s join v$lock l on s.sid = l.sid where s.wait_class != 'idle' and l.request > 0;
如果查询结果显示有多个会话在等待锁,可能存在数据库阻塞问题。
-
使用 dba_waiters 和 dba_blockers 视图:在 sql*plus 或其他 sql 工具中,查询 dba_waiters 和 dba_blockers 视图。这两个视图提供了有关阻塞会话和等待会话的详细信息。以下是一个查询示例:
select w.waiting_session, w.blocking_session, w.wait_time, w.lock_type from dba_waiters w join dba_blockers b on w.blocking_session = b.holding_session;
如果查询结果显示有多个会话在等待锁,可能存在数据库阻塞问题。
-
使用自动数据库诊断监视器 (addm) 报告:addm 报告提供了有关数据库性能问题的详细信息,包括锁争用和阻塞。检查 addm 报告中的 “global cache” 部分,以查看是否存在锁争用或阻塞问题。
-
tanel poder几个脚本会很有用
@swc sid||':'||serial#||':'||event||':'||username||':'||inst_id||':'||username 1=1
@dash_wait_chains username||':'||':'||session_id||':'||session_serial#||':'||event2||':'||program2||':'||time_model_name||':'||objt session_type='foreground' "timestamp'2023-04-20 00:00:00'" "timestamp'2023-04-21 00:00:00'"
@dash_wait_chains username||':'||':'||session_id||':'||session_serial#||':'||event2||':'||program2||':'||time_model_name session_type='foreground' sysdate-1 sysdate
@ash_wait_chains username||':'||':'||session_id||':'||session_serial#||':'||event2||':'||program2||':'||time_model_name||':'||objt session_type='foreground' "timestamp'2023-04-20 00:00:00'" "timestamp'2023-04-21 00:00:00'"
@ash_wait_chains username||':'||':'||session_id||':'||session_serial#||':'||event2||':'||program2||':'||time_model_name session_type='foreground' sysdate-1 sysdate
通过以上方法,可以初步判断数据库阻塞是否导致 sql 执行效率低下。如果确定存在数据库阻塞问题,可以进一步分析锁争用的原因,并采取相应的优化措施。例如,优化事务处理逻辑,减少长时间持有锁的操作,或使用乐观锁等。
九. 应用程序设计问题
要判断应用程序设计问题是否导致 sql 执行效率低下,可以参考以下方法和命令:
-
检查 sql 执行统计信息:
使用v$sql
或v$sqlarea
视图查找执行次数高、cpu 时间长或磁盘读取次数多的 sql 语句。例如:select sql_id, executions, elapsed_time, cpu_time, disk_reads, buffer_gets from v$sql where buffer_gets > 10000 order by elapsed_time desc;
-
分析 sql 语句执行计划:
使用explain plan
命令或dbms_xplan.display_cursor
函数查看 sql 语句的执行计划,分析是否存在全表扫描、笛卡尔积连接等低效操作。例如:explain plan for select * from employees e, departments d where e.department_id = d.department_id; select * from table(dbms_xplan.display);
-
分析会话等待事件:
使用v$session_event
或v$session_wait
视图查看会话等待事件,检查是否存在锁等待、磁盘 i/o 等待等性能瓶颈。例如:select event, total_waits, time_waited from v$session_event where sid = 123;
-
检查数据库性能诊断报告:
生成 awr 报告、ash 报告或使用 enterprise manager 工具分析数据库性能,找出潜在的应用程序设计问题。例如,创建 awr 报告:select * from table(dbms_workload_repository.awr_report_text(
, , , )); -
使用 sql trace 和 tkprof 工具:
使用 sql trace 功能追踪会话中的 sql 语句执行情况,然后使用 tkprof 工具分析生成的 trace 文件。例如,启用 sql trace 和 tkprof 分析:alter session set tracefile_identifier = 'my_trace'; alter session set events '10046 trace name context forever, level 12'; -- 在此执行 sql 语句 alter session set events '10046 trace name context off';
使用 tkprof 分析 trace 文件:
tkprof my_trace.trc my_trace_analysis.txt sys=no explain=user/password
结合以上方法和命令,可以找出潜在的应用程序设计问题,从而针对性地优化 sql 语句和应用程序代码。注意,针对性能问题的调优可能需要多次迭代,不断地监控和分析数据库性能,才能找到最佳的m6米乐安卓版下载的解决方案。
十. 其他数据库对象问题
其他数据库对象问题可能导致 sql 执行效率变低,具体方法和命令如下:
-
索引问题:
- 索引损坏:使用
analyze index
检查索引结构,修复损坏的索引。validate structure; - 索引失效:重新收集索引统计信息,例如:
exec dbms_stats.gather_index_stats('
。', ' '); - 使用不当的索引:检查 sql 语句的执行计划,优化 sql 语句或修改索引以提高执行效率。
- 索引损坏:使用
-
数据库对象统计信息过期或不准确:
- 重新收集表、索引和列的统计信息,例如:
exec dbms_stats.gather_schema_stats('
。');
- 重新收集表、索引和列的统计信息,例如:
-
分区表问题:
- 分区键不合理:分析分区键的选择,优化分区键以提高查询效率。
- 分区表统计信息不准确:重新收集分区表和子分区的统计信息,例如:
exec dbms_stats.gather_table_stats('
。', ' ', granularity => 'partition');
-
触发器和存储过程问题:
- 检查触发器和存储过程中的 sql 语句,优化逻辑以提高执行效率。
- 检查触发器是否导致行级锁争用,优化触发器逻辑以减少锁争用。
-
数据库对象依赖关系问题:
- 检查视图、同义词和存储过程的依赖关系,优化对象结构以提高查询效率。
- 使用
dbms_utility.compile_schema
编译无效对象,例如:exec dbms_utility.compile_schema('
。');
-
lob 对象问题:
- 优化 lob 存储参数以提高查询效率,例如:修改 lob 段的存储子句,使用
cache
或nocache
选项。 - 重新组织 lob 数据以提高查询效率,例如:使用
dbms_redefinition
重新定义 lob 列。
- 优化 lob 存储参数以提高查询效率,例如:修改 lob 段的存储子句,使用
-
其他对象问题:
- 使用
dbms_redefinition
在线重新组织表以提高查询效率。 - 清理无用的数据库对象,例如:删除不再使用的表、索引、视图和存储过程。
- 使用
通过结合以上方法和命令,可以检查和优化数据库对象,从而提高 sql 执行效率。请注意,性能调优可能需要多次迭代,不断地监控和分析数据库性能,才能找到最佳的m6米乐安卓版下载的解决方案。
十一、偷梁换柱替换执行计划
1、使用sql_profile直接替换
1、停用原基线
sql> declare
2 rs pls_integer;
3 begin
4 rs:=dbms_spm.alter_sql_plan_baseline (
5 plan_name=>'sql_plan_a6bmz0rdcvsk7ecfa9855',
6 attribute_name=>'enabled',
7 attribute_value=>'no');
8 end;
9 /
pl/sql procedure successfully completed.
2、连接新基线
sql> declare
2 ln_ps pls_integer;
3 begin
4 ln_ps:=dbms_spm.load_plans_from_cursor_cache
5 (sql_id=>'8uvxtbn283qwz', --带hint的sql
6 plan_hash_value=>3321871023,
7 sql_handle=>'sql_a32e7f05dacde247' --不带hint的sql_handle
8 );
9 end;
10 /
pl/sql procedure successfully completed.
sql> select count(*) from t2 where deptno=10;
count(*)
----------
524289
sql> select * from table(dbms_xplan.display_cursor);
plan_table_output
------------------------------------------------------------------------------------------------------------------------------------------------------
sql_id bt33t77y2w9mf, child number 1
-------------------------------------
select count(*) from t2 where deptno=:"sys_b_0"
plan hash value: 3321871023
---------------------------------------------------------------------------
| id | operation | name | rows | bytes | cost (%cpu)| time |
---------------------------------------------------------------------------
| 0 | select statement | | | | 1105 (100)| |
| 1 | sort aggregate | | 1 | 3 | | |
|* 2 | table access full| t2 | 524k| 1536k| 1105 (1)| 00:00:01 |
---------------------------------------------------------------------------
predicate information (identified by operation id):
---------------------------------------------------
2 - filter("deptno"=:sys_b_0)
note
-----
- sql plan baseline sql_plan_a6bmz0rdcvsk71c6cf506 used for this statement
2、使用coe_xfr_sql_profile脚本替换执行计划
- 方法1、替换sql_plan_id
@coe_xfr_sql_profile.sql 6wk7ggz469b7u 1601196873 --分别传入sqlid和需要的执行计划,之后执行生成的脚本
-方法2、替换outline
@coe_xfr_sql_profile 6wk7ggz469b7u 2296882198 --慢
@coe_xfr_sql_profile 6wk7ggz469b7u 1601196873 --块
将慢sql得outline替换为快sql得outline
十二、其它常用脚本
--统计信息收集时间
select owner,table_name,tablespace_name,to_char(last_analyzed,'yyyymmdd hh24:mi:ss') from dba_tables where table_name='xxx';
--统计信息是否过期
col subpartition_name for a50
select subpartition_name,owner,table_name,last_analyzed,stale_stats,object_type,partition_name from dba_tab_statistics where owner='xxx' and table_name='xxxx' ;
--sql内容
select sql_id,sql_text from v$sql where sql_text like
--历史执行计划
select distinct sql_id,plan_hash_value,to_char(timestamp, 'yyyy-mm-dd hh24:mi:ss') timestamp from dba_hist_sql_plan where sql_id='0516w6n85ycsp' order by timestamp;
--历史执行计划详细
col options for a15;
col operation for a20;
col object_name for a20;
select to_char(plan_hash_value),id,operation,options,object_name,depth,cost,to_char(timestamp,'yyyymmdd hh24:mi:ss') from dba_hist_sql_plan where sql_id='0516w6n85ycsp' and plan_hash_value in (2178614564,2370451839) order by plan_hash_value,id,timestamp;
--awr执行计划
select* from table(dbms_xplan.display_awr('0516w6n85ycsp',null));
select * from table(dbms_xplan.display_cursor('&sql_id',null,'typical peeked_binds'));
--清理执行计划游标
select address,to_char(hash_value) from v$sqlarea where sql_id='0516w6n85ycsp';
exec dbms_shared_pool.purge('000000020430dbb0,274674453','c');
--历史执行计划
col snap_id for 99999999
col date_time for a30
col plan_hash for 9999999999
col executions for 99999999
col avg_etime_s heading 'etime/exec' for 9999999.99
col avg_lio heading 'buffer/exec' for 99999999999
col avg_pio heading 'diskread/exec' for 99999999999
col avg_cputime_s heading 'cputim/exec' for 9999999.99
col avg_row heading 'rows/exec' for 9999999
select * from(select distinct s.snap_id,to_char(s.begin_interval_time,'mm/dd/yy_hh24mi') || to_char(s.end_interval_time,'_hh24mi') date_time,
sql.plan_hash_value plan_hash,sql.executions_delta executions,(sql.elapsed_time_delta/1000000)/decode(sql.executions_delta,null,1,0,1,sql.executions_delta) avg_etime_s,
sql.buffer_gets_delta/decode(sql.executions_delta,null,1,0,1,sql.executions_delta) avg_lio,
sql.disk_reads_delta/decode(sql.executions_delta,null,1,0,1,sql.executions_delta) avg_pio,
(sql.cpu_time_delta/1000000)/decode(sql.executions_delta,null,1,0,1,sql.executions_delta) avg_cputime_s,
sql.rows_processed_total/decode(sql.executions_delta,null,1,0,1,sql.executions_delta) avg_row
from dba_hist_sqlstat sql, dba_hist_snapshot s
where sql.instance_number =(select instance_number from v$instance)
and sql.dbid =(select dbid from v$database)
and s.snap_id = sql.snap_id
and sql_id = trim('&sql_id') order by s.snap_id desc)
where rownum <= 100;
--检查spm
select sql_handle, plan_name, origin from dba_sql_plan_baselines where sql_text like 'select /*for_test*/ * from test1%';
--高水位
select table_name,round ( (blocks * 8), 2) "高水位空间 k",round ( (num_rows * avg_row_len / 1024), 2) "真实使用空间 k",round ( (blocks * 10 / 100) * 8, 2) "预留空间(pctfree) k",round ( (blocks * 8 - (num_rows * avg_row_len / 1024)- blocks * 8 * 10 / 100),2)" 浪费空间 k" from dba_tables where temporary = 'n' and table_name ='crm_dataserv_figure' order by 5 desc;
--yong.zhao
--查询sql历史执行性能消耗情况,默认sysdate-7,可修改
select 'gv$' flag,
0 snap_id,
inst_id,
plan_hash_value phv,
executions execs,
disk_reads reads,
disk_reads / decode(executions, null, 1, 0, 1, executions) reads_per,
buffer_gets gets,
buffer_gets / decode(executions, null, 1, 0, 1, executions) gets_per,
rows_processed,
rows_processed / decode(executions, null, 1, 0, 1, executions) rows_per,
elapsed_time/1000 elap_ms,
(elapsed_time/1000) / decode(executions, null, 1, 0, 1, executions) elap_per_ms
from gv$sql
where sql_id='&sql_id'
union all
select to_char(sht.begin_interval_time,'dd hh24:mi')||'--'||to_char(sht.end_interval_time,'hh24:mi') flag,
sta.snap_id,
sta.instance_number inst,
sta.plan_hash_value phv,
sta.executions_delta execs,
sta.disk_reads_delta reads,
sta.disk_reads_delta /
decode(sta.executions_delta, null, 1, 0, 1, sta.executions_delta) reads_per,
sta.buffer_gets_delta gets,
sta.buffer_gets_delta /
decode(sta.executions_delta, null, 1, 0, 1, sta.executions_delta) gets_per,
sta.rows_processed_delta,
sta.rows_processed_delta /
decode(sta.executions_delta, null, 1, 0, 1, sta.executions_delta) rows_per,
sta.elapsed_time_delta/1000 elap_ms,
(sta.elapsed_time_delta/1000) /
decode(sta.executions_delta, null, 1, 0, 1, sta.executions_delta) elap_per_ms
from dba_hist_sqlstat sta,dba_hist_snapshot sht
where 1=1
and sta.instance_number=sht.instance_number
and sta.snap_id=sht.snap_id
and sht.begin_interval_time>= sysdate-7
and sta.sql_id='&sql_id'
order by 1,2;