I was given a SQL query, saying that I have to optimize this query.
I came accross explain plan. So, in SQL developer, I ran explain plan for ,
It divided the query into different parts and showed the cost for each of them.
How do I go about optimizing the query? What do I look for? Elements with high costs?
I am a bit new to DB, so if you need more information, please ask me, and I will try to get it.
I am trying to understand the process rather than just posting the query itself and getting the answer.
The query in question:
SELECT cr.client_app_id,
cr.personal_flg,
r.requestor_type_id
FROM credit_request cr,
requestor r,
evaluator e
WHERE cr.evaluator_id = 96 AND
cr.request_id = r.request_id AND
cr.evaluator_id = e.evaluator_id AND
cr.request_id != 143462 AND
((r.soc_sec_num_txt = 'xxxxxxxxx' AND
r.soc_sec_num_txt IS NOT NULL) OR
(lower(r.first_name_txt) = 'test' AND
lower(r.last_name_txt) = 'newprogram' AND
to_char(r.birth_dt, 'MM/DD/YYYY') = '01/02/1960' AND
r.last_name_txt IS NOT NULL AND
r.first_name_txt IS NOT NULL AND
r.birth_dt IS NOT NULL))
On running explain plan, I am trying to upload the screenshot.
OPERATION OBJECT_NAME OPTIONS COST
SELECT STATEMENT 15
NESTED LOOPS
NESTED LOOPS 15
HASH JOIN 12
Access Predicates
CR.EVALUATOR_ID=E.EVALUATOR_ID
INDEX EVALUATOR_PK UNIQUE SCAN 0
Access Predicates
E.EVALUATOR_ID=96
TABLE ACCESS CREDIT_REQUEST BY INDEX ROWID 11
INDEX CRDRQ_DONE_EVAL_TASK_REQ_NDX SKIP SCAN 10
Access Predicates
CR.EVALUATOR_ID=96
Filter Predicates
AND
CR.EVALUATOR_ID=96
CR.REQUEST_ID<>143462
INDEX REQUESTOR_PK RANGE SCAN 1
Access Predicates
CR.REQUEST_ID=R.REQUEST_ID
Filter Predicates
R.REQUEST_ID<>143462
TABLE ACCESS REQUESTOR BY INDEX ROWID 3
Filter Predicates
OR
R.SOC_SEC_NUM_TXT='XXXXXXXX'
AND
R.BIRTH_DT IS NOT NULL
R.LAST_NAME_TXT IS NOT NULL
R.FIRST_NAME_TXT IS NOT NULL
LOWER(R.FIRST_NAME_TXT)='test'
LOWER(R.LAST_NAME_TXT)='newprogram'
TO_CHAR(INTERNAL_FUNCTION(R.BIRTH_DT),'MM/DD/YYYY')='01/02/1960'
After refactoring the query comes indexes, so following on from @eric’s post:
credit_request:You’re joining this onto
requestoronrequest_id, which I hope is unique. In your where clause you then have a condition onevaluator_idand selectclient_app_idandpersonal_flgin the query. So, you probably need a unique index, oncredit_requestof(request_id, evaulator_id, client_app_id, personal_flg.By putting the columns you’re selecting into the index you avoid the
by index rowid, which means that you have selected your values from the index then re-entered the table to pick up more information. If this information is already in the index then there’s no need.You’re joining it onto
evaluatoronevaluator_id, which is included in the first index.requestor:This is being joined onto on
request_idand your where clause includesoc_sec_num_text,lower(first_name_txt),lower(last_name_txt)andbirth_dt. So, you need a unique if possible, index on(request_id, soc_sec_num_text)because of the or this is further complicated because you should really have an index on as many of the conditions as possible. You’re also selectingrequestor_type_iud.In this case to avoid a functional index, with many columns, I’d index on
(request_id, soc_sec_num_text, birth_dt )if you have the space, time and inclination then addinglower(first_name_txt)... etcto this may improve the speed depending on how selective the column is. This means that if there are far more values in for instance,first_name_txtthanbirth_dtyou’d be better of putting this in front ofbirth_dtin the index so your query has less to scan if it’s a non-unique index.You notice that I haven’t added the selected column into this index as you’re already going to have to go into the table so you gain nothing by adding it.
evaluator:This is only being joined on
evaluator_idso you need a unique, if possible, index on this column.