当前位置:网站首页>78- several methods to solve SQL performance problems without changing code in production system

78- several methods to solve SQL performance problems without changing code in production system

2022-06-22 21:22:00 Tiger Liu

A large part of database performance is similar to SQL Related to writing method , There are some SQL Must change the code to optimize , If you can't change the code , You need to delete the history , Recycle space , Keep the table relatively small all the time , To consume less resources , Get an acceptable response time . As mentioned in the previous official account article : Must be overwritten SQL To improve performance ( List 10 A need to rewrite SQL).

For a variety of reasons , Need not change SQL Optimize the database in the case of code , Here are some cases , You can do this without changing the program code , improve SQL Efficiency of execution :

1- Add index ( There is no risk )

General index :

This is not much to explain , Most of the sql Performance improvements are immediate , Hundreds of times , Thousands or even tens of thousands of times of improvement is normal .

Function index

Solve implicit type conversion :

The field type is varchar2 type , The variable type is number type , such as phone_nbr=13812345678 , phone_nbr(varchar2 type ) The index on the field is useless ( Don't argue index fast full scan Are likely to ), You need to create another one to_number(phone_nbr) To improve efficiency ;

In a similar situation varchar2 type ( and char type ) Field of , The variable type is nvarchar2( and nchar), This situation requires the creation of to_nchar Function index ;

Be careful : date Type field , run into sb. timestamp The variable of , Cannot create to_timestamp Function index to solve , You need to use the method 3.

Solve the problem of using functions on fields , Do calculations :

to_char(cdate,'yyyymmdd')=:b1

You can create to_char(cdate,'yyyymmdd') Function index

xxx is null Writing , It can make xxx And constants 0 Form a joint index

2- Adjust the execution plan ( There is no risk )

sql Execution plan selection error , You don't need to be in the... Of the program code sql add hint, Powerful oracle There's a way to control... In the background SQL Implementation plan of ;

situation 1: The execution plan is good or bad , Use it directly sql profile or sql plan baseline Fixed execution plan ;

situation 2:sql There is no good implementation plan , Need to add... Manually hint Generate a good execution plan , And then use sql profile or sql plan baseline Fix ;

Both of the above can be used coe_load_sql_profile.sql Script completion , Simply enter a few parameters .

For the situation 2, Many books introduce the use of coe_xfr_sql_profile.sql, This method is troublesome , It's easy to make mistakes , I suggest you abandon this method , Use simple coe_load_sql_profile.sql

Add a hint Use special cases , /*+ bind_aware */ This hint, Need to use sql patch Add .

The reason for writing this official account is a question from a former colleague. :

A system tool (logminer) The use of sql, The parallelism used is 208 Of parallel_index , Such a high degree of parallelism is unacceptable , Want to cancel sql Parallel of . Because you can't modify SQL, Try to use no_parallel_index(t) Don't take effect , Finally through sql patch Applied a full([email protected]$1) Of hint, Avoid using index fast full scan, There will be no parallelism :

3- Change field type ( There is a certain risk , It is recommended to do a full test )

Mainly aimed at date The type field , encounter timestamp Variable of type , The index cannot be used for implicit type conversion , Such as :

select count(*) from tt where created>=:b1 and created<=:b2;

If created The fields are date type ,b1 and b2 yes timestamp type , Implicit type conversion happens , Can't use created Index on field ; And this situation cannot be created to_timestamp Function index to remedy ;

If you don't change the code, solve , Only field types can be modified date by timestamp(0):

alter table tt modify created timestamp(0);

This statement only modifies the data dictionary , There is no need to modify each line of record ( If it's the other way around timestamp(0) Change to date type , You have to modify each record line by line , Big watch will take a long time )

timestamp(0) And date The main difference between types is Two timestamp Subtracting types yields interval type ; And two date Type subtraction , Get is number type , If there is no such predicate condition or return column , You can try this method .

4- Change the table structure ( There is no risk )

Change to partition table

apply : Statistical analysis SQL, If it is a statistical analysis of one month's data , Table has 5 The amount of data for the year , After partition , The data access volume is the original 1/60

5- Change parameters ( There is a certain risk , It is recommended to do a full test )

OLTP High concurrency environments do not use bound variables , A lot of hard parsing , The workload of modifying the code is huge , The simple way is to modify the database initialization parameters cursor_sharing=force ( The default value is exact), There are certain risks , Do a good test .( Somewhat bug We need to pay attention to , Official account : 11.2.0.3 Version upgrade to 18c Previous versions , You may encounter serious performance problems )

6- Special cases

primary SQL:

select PM_JOB_SEQUENCE.nextval job_id

from (select 1 from all_objects where rownum <= 13);

Borrow data dictionary view all_objects Generate a paragraph sequence Sequence , Frequent execution , Consume a large amount of CPU, Average per execution buffer gets 169~1362(6 Execution plans ):

If you can change the code , You can change to :

select PM_JOB_SEQUENCE.nextval job_id from dual connect by level<=13;

This way of writing does not consume buffer gets;

If you can't change the code , You can create a table with the same name :

create table all_objects (id number not null);

insert into all_objects select 0 from dual connect by level<=100;

commit;

create index idx_all_objects on all_objects(id);

-- Because synonyms synonym When it exists at the same time as the table , Optimize access tables , All that is needed is 2 individual buffer gets:

select PM_JOB_SEQUENCE.nextval job_id

from (select 1 from all_objects where rownum <= 13);

If you want to access the real system view all_objects, You need to add sys Of schema: sys.all_objects

7- DBMS_ADVANCED_REWRITE ( Method 6, If you just change your watch , It can also be done in this way , But not supported sequence)

This method is 10g The version has , Use a paragraph SQL Code , Replace another paragraph SQL Code ( With bound variables is not supported SQL), It's very powerful , If you are interested, you can search for more cases on the Internet .

Corresponding data dictionary : DBA_REWRITE_EQUIVALENCES

Here is a simple example :

Parameter description :

DBMS_ADVANCED_REWRITE.DECLARE_REWRITE_EQUIVALENCE (

name VARCHAR2, --- name

source_stmt CLOB, --- primary SQL Code

destination_stmt CLOB, --- Replace SQL Code

validate BOOLEAN := TRUE, -- The default value is true, Will compare two SQL Result set , If it's not the same , Will not be created successfully

rewrite_mode VARCHAR2 := 'TEXT_MATCH' -- The default value is , Simple conversion ; There are also advanced ones general, More advanced recursive (disabled: Ban )

);

If you want to delete :

exec sys.DBMS_ADVANCED_REWRITE.DROP_REWRITE_EQUIVALENCE ('&equ_name');

-- The example begins :

-- establish REWRITE_EQUIVALENCE

begin

sys.DBMS_ADVANCED_REWRITE.DECLARE_REWRITE_EQUIVALENCE (

'tiger_test_equivalence',

'select ename from emp',

'select dname from dept'

,validate => false

);

end;

/

-- Modify parameters to use :query_rewrite_integrity The default value is : enforced

SQL> alter session set query_rewrite_integrity = trusted;

-- below SQL, It's actually executing select dname from dept:

SQL>select ename from emp;

ENAME

--------------

ACCOUNTING

RESEARCH

SALES

OPERATIONS

-- Put parameters query_rewrite_integrity Change back to the default

alter session set query_rewrite_integrity = enforced;

-- Re execution , Return normal results :

SQL> select ename from emp;

ENAME

----------

SMITH

ALLEN

......

JAMES

FORD

MILLER

Actual combat case simulation :

-- primary SQL, Can't use status Index on field ( The condition is written having part ):

select m.object_type, count(1) unread_count

from t1 m

group by m.object_type, m.status, m.owner

having m.status = 'INVALID' and m.owner = 'SYS';

-- Equivalent rewriting SQL, have access to status Index on field ( The condition is where part ):

select m.object_type, count(1) unread_count

from t1 m where m.status = 'INVALID' and m.owner = 'SYS'

group by m.object_type, m.status, m.owner;

Want to rewrite with equivalent SQL, Replace the original SQL, Here are a few simple steps :

setup case:

create table t1 as select * from dba_objects;

create index idx_t1_status on t1(status);

-- establish REWRITE_EQUIVALENCE

begin

sys.DBMS_ADVANCED_REWRITE.DECLARE_REWRITE_EQUIVALENCE (

'test_rewrite2'

, q'[select m.object_type, count(1) unread_count

from t1 m

group by m.object_type, m.status, m.owner

having m.status = 'INVALID' and m.owner = 'SYS']'

, q'[select m.object_type, count(1) unread_count

from t1 m where m.status = 'INVALID' and m.owner = 'SYS'

group by m.object_type, m.status, m.owner]'

, validate => true

, rewrite_mode => 'general'

);

end;

/

-- Execute original SQL, Execute plan or use full table scan (query_rewrite_integrity Parameter not set )

select m.object_type, count(1) unread_count

from t1 m

group by m.object_type, m.status, m.owner

having m.status = 'INVALID' and m.owner = 'SYS';

-- Set parameters , Execute the original... Again SQL:

alter session set query_rewrite_integrity = trusted;

select m.object_type, count(1) unread_count

from t1 m

group by m.object_type, m.status, m.owner

having m.status = 'INVALID' and m.owner = 'SYS';

( It is equivalent to executing the rewritten SQL, The purpose of optimization is realized )

8- Unconventional method , Use with caution !

Change in binary code sql (jar,exe Wait for the documents ,sql The code is generally saved as a string ) ; Most of the time , This method should also be no problem . however , Last resort , Don't use this trick . Do a good test .

A simple example :

sql The code has format conversion of various date types , The following situations need to be created 3 Different functional indexes :

to_char(created,'yyyy-mm-dd') / to_char(created,'yyyy/mm/dd') / to_char(created,'yyyymmdd')

This situation , Can be in binary code , Find these strings , Change unity to to_char(created,'yyyymmdd') , In this way, you only need to create a functional index .

The first two words , After modification, the length of the string becomes shorter , You can fill in two blanks after it .

Thank you for reading

( End )

原网站

版权声明
本文为[Tiger Liu]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/173/202206221910054329.html