Please start any new threads on our new site at https://forums.sqlteam.com. We've got lots of great SQL Server experts to answer whatever question you can come up with.

 All Forums
 SQL Server 2008 Forums
 Transact-SQL (2008)
 Can this query be optimized?

Author  Topic 

vaibhavktiwari83
Aged Yak Warrior

843 Posts

Posted - 2011-12-02 : 05:38:24
[code]
SELECT
CLAIM_KEY,
CHART_KEY,
CPTCODE,
CASE WHEN A.Component = '1' THEN ICD9CODE1
WHEN A.Component = '2' THEN ICD9CODE2
WHEN A.Component = '3' THEN ICD9CODE3
WHEN A.Component = '4' THEN IDC9CODE4
END
AS ICD9CODE,
A.Component AS Diagnosis_Number
FROM
(
SELECT CLAIM_KEY,
CHART_KEY,
CPTCODE,
ICD9CODE1,
ICD9CODE2,
ICD9CODE3,
IDC9CODE4,
DX_NUM
FROM ENCOUNTER
) T
CROSS APPLY
(
SELECT * FROM SplitString(DX_NUM,',')
)A
[/code]


Vaibhav T

If I cant go back, I want to go fast...

visakh16
Very Important crosS Applying yaK Herder

52326 Posts

Posted - 2011-12-02 : 06:01:29
whats the issue with posted query?

------------------------------------------------------------------------------------------------------
SQL Server MVP
http://visakhm.blogspot.com/

Go to Top of Page

nigelrivett
Master Smack Fu Yak Hacker

3385 Posts

Posted - 2011-12-02 : 06:02:36
Not sure what that's doing but maybe this
(Could populate a temp table using the PK, index it and join to it rather than use the cte in the query - test to see what's best.)


declare @ENCOUNTER table (CLAIM_KEY int, CHART_KEY int, CPTCODE int, DX_NUM varchar(20), ICD9CODE1 int, ICD9CODE2 int, ICD9CODE3 int, ICD9CODE4 int)
insert @ENCOUNTER select 1, 1, 1, '1,2,3', 1, 2, 3, 4
insert @ENCOUNTER select 2, 2, 2, '3,4', 1, 2, 3, 4
insert @ENCOUNTER select 3, 3, 3, '2', 1, 2, 3, 4

;with cte as
(
select distinct DX_NUM, i=1, j=CHARINDEX(',',DX_NUM) from @ENCOUNTER where DX_NUM <> ''
union all
select DX_NUM, i=j+1, j=CHARINDEX(',',DX_NUM,j+1) from cte where j <> 0
) ,
cte2 as
(
select DX_NUM, i, j = case when j = 0 then LEN(DX_NUM)+1 else j end from cte
),
cte3 as
(
select DX_NUM, Component = SUBSTRING(DX_NUM,i,j-i) from cte2
)
SELECT
CLAIM_KEY,
CHART_KEY,
CPTCODE,
CASE
WHEN A.Component = '1' THEN ICD9CODE1
WHEN A.Component = '2' THEN ICD9CODE2
WHEN A.Component = '3' THEN ICD9CODE3
WHEN A.Component = '4' THEN ICD9CODE4
END AS ICD9CODE,
A.Component AS Diagnosis_Number
FROM @ENCOUNTER e
join cte3 A
on A.DX_NUM = e.DX_NUM

CLAIM_KEY CHART_KEY CPTCODE ICD9CODE Diagnosis_Number
----------- ----------- ----------- ----------- --------------------
1 1 1 1 1
3 3 3 2 2
2 2 2 3 3
2 2 2 4 4
1 1 1 2 2
1 1 1 3 3

==========================================
Cursors are useful if you don't know sql.
SSIS can be used in a similar way.
Beer is not cold and it isn't fizzy.
Go to Top of Page

vaibhavktiwari83
Aged Yak Warrior

843 Posts

Posted - 2011-12-02 : 06:07:03
@Visakh : I have minimize the query as ENCOUNTER Table has joins with 6-7 tables more and few more columns are there in select.

this query is taking 7-8 minutes to process hardly 60-70 rows.

I wanted to rewrite the query in different way as I doubt cross apply is taking much time....

Vaibhav T

If I cant go back, I want to go fast...
Go to Top of Page

vaibhavktiwari83
Aged Yak Warrior

843 Posts

Posted - 2011-12-02 : 06:08:14
@nigelrivett : thanks for your reply. Let me customize your query and test it. I will let you know shortly...

Vaibhav T

If I cant go back, I want to go fast...
Go to Top of Page

visakh16
Very Important crosS Applying yaK Herder

52326 Posts

Posted - 2011-12-02 : 06:09:40
i cant see any filter on ENCOUNTER table. Are you sure you want to process entire records of ENCOUNTER? also whats SplitString returning? whats the purpose of CASE in SELECT?

------------------------------------------------------------------------------------------------------
SQL Server MVP
http://visakhm.blogspot.com/

Go to Top of Page

vaibhavktiwari83
Aged Yak Warrior

843 Posts

Posted - 2011-12-02 : 06:37:37
There is a date filter on inner result set.
nigelrivett created sample data.
SplitString splict comma seperated value for ex 1,2,3
and those values of column is came into rows
and depend upon those values columns are selected.

Vaibhav T

If I cant go back, I want to go fast...
Go to Top of Page

vaibhavktiwari83
Aged Yak Warrior

843 Posts

Posted - 2011-12-02 : 06:38:45
@nigelrivett : Its taking very much time to process with filter of single record having 9-10 rows.

Vaibhav T

If I cant go back, I want to go fast...
Go to Top of Page

vaibhavktiwari83
Aged Yak Warrior

843 Posts

Posted - 2011-12-02 : 06:39:48
Below is the original query -


SELECT
C.CLAIM_KEY,T.TRANSACTION_ZZ,
-- Below flag is set same as CLAIM_CHART_CPTCODE Charge correction
CASE WHEN I.CHG_CORR_FLAG IN ('ORIGINAL', 'REVERSAL') THEN 1
WHEN I.CHG_CORR_REASON != 0 THEN 1
WHEN I.CORR_INV_NUM IS NOT NULL THEN 1
WHEN I.FSC = 5 THEN 1
ELSE 0
END AS CHARGE_CORRECT_F,
E.CHART_KEY,
CPT.PROCEDURE_CODE CPTCODE,
DIAG1.ICD_9_CM_CODE ICD9CODE1,
DIAG2.ICD_9_CM_CODE ICD9CODE2,
DIAG3.ICD_9_CM_CODE ICD9CODE3,
DIAG4.ICD_9_CM_CODE IDC9CODE4,
T.DX_NUM,
CASE WHEN A.Component = '1' THEN DIAG1.ICD_9_CM_CODE
WHEN A.Component = '2' THEN DIAG2.ICD_9_CM_CODE
WHEN A.Component = '3' THEN DIAG3.ICD_9_CM_CODE
WHEN A.Component = '4' THEN DIAG4.ICD_9_CM_CODE
END ICD9CODE,
A.Component AS Diagnosis_Number,
A.Id AS LinkageID
FROM
STG_P_FC_PATIENT P
INNER JOIN STG_P_FC_INVOICE I ON P.PATIENT = I.PATIENT and i.GROUP_ZZ != 101 -- remove urgent care data
INNER JOIN STG_P_TRANSAC T ON T.PATIENT = I.PATIENT
AND T.INVOICE = I.INVOICE
AND T.GROUP_ZZ = I.GROUP_ZZ
INNER JOIN CLAIM C ON C.PATIENT_NBR = I.PATIENT
AND C.GROUP_NBR = I.GROUP_ZZ AND C.INVOICE = I.INVOICE
INNER JOIN ENCOUNTER E ON E.OLD_ENCOUNTER_ID = P.OTH_NUM AND E.OLD_ENCOUNTER_ID >= '20000000'
INNER JOIN STG_P_DN1_CPTCODE CPT ON T.PROC_ZZ = CPT.RECORD_NUMBER
INNER JOIN STG_P_DN36_ICD9 DIAG1 ON I.DX_ONE = DIAG1.RECORD_NUMBER
LEFT JOIN STG_P_DN36_ICD9 DIAG2 ON I.DX_TWO = DIAG2.RECORD_NUMBER
LEFT JOIN STG_P_DN36_ICD9 DIAG3 ON I.DX_THREE = DIAG3.RECORD_NUMBER
LEFT JOIN STG_P_DN36_ICD9 DIAG4 ON I.DX_FOUR = DIAG4.RECORD_NUMBER
CROSS APPLY
(
SELECT * FROM SplitString(T.DX_NUM,',')
)A
where
E.OLD_ENCOUNTER_ID = '30398208'



Vaibhav T

If I cant go back, I want to go fast...
Go to Top of Page

visakh16
Very Important crosS Applying yaK Herder

52326 Posts

Posted - 2011-12-02 : 06:40:32
can you analyse the query execution plan and see what are costly steps?

------------------------------------------------------------------------------------------------------
SQL Server MVP
http://visakhm.blogspot.com/

Go to Top of Page

nigelrivett
Master Smack Fu Yak Hacker

3385 Posts

Posted - 2011-12-02 : 06:57:52
What is the size of the table.
How many distinct values for DX_NUM are there.
Try running the ctes separately and see if they take a long time - or which one is the issue.
indexing DX_NUM would help for the first one.


==========================================
Cursors are useful if you don't know sql.
SSIS can be used in a similar way.
Beer is not cold and it isn't fizzy.
Go to Top of Page

Transact Charlie
Master Smack Fu Yak Hacker

3451 Posts

Posted - 2011-12-02 : 11:13:41
Post the code for SplitString


There are many different ways to split the string and they have *vastly* different performance envelopes.

Charlie
===============================================================
Msg 3903, Level 16, State 1, Line 1736
The ROLLBACK TRANSACTION request has no corresponding BEGIN TRANSACTION
Go to Top of Page

Transact Charlie
Master Smack Fu Yak Hacker

3451 Posts

Posted - 2011-12-02 : 11:42:13
but I guess there's probably more chance of it being some horrible join implementation caused by lack of index / non possible index using join if you are having problems on 10 rows.

Charlie
===============================================================
Msg 3903, Level 16, State 1, Line 1736
The ROLLBACK TRANSACTION request has no corresponding BEGIN TRANSACTION
Go to Top of Page

vaibhavktiwari83
Aged Yak Warrior

843 Posts

Posted - 2011-12-03 : 07:12:11
Thanks everyone for the replies.

I tried to take the data in temp table instead of CTE.
and joined back to the main query rather than cross apply.

Below is rewritten code.

Now its taking less then one and half minutes.



SELECT
GROUP_ZZ, PATIENT, INVOICE, TRANSACTION_ZZ ,DX_NUM ,PROC_ZZ,a.Component,a.Id
into #tmp
FROM STG_P_TRANSAC
CROSS APPLY
(
SELECT * FROM SplitString(DX_NUM,',')
)A
WHERE PROC_ZZ>0 AND UPDATE_DT BETWEEN @pdteBeginDate AND @pdteEndDate

CREATE CLUSTERED INDEX [IDX_tmp]
ON [#tmp]
([PATIENT],[GROUP_ZZ],[INVOICE],[TRANSACTION_ZZ],[DX_NUM],[PROC_ZZ])

SELECT
AA.CHART_KEY,
CLAIM_KEY,
ICD9CODE,
CPTCODE,
TRANSACTION_ZZ,
CHARGE_CORRECT_F,
Diagnosis_Number,
LinkageID
FROM
(
SELECT
C.CLAIM_KEY,T.TRANSACTION_ZZ,

CASE WHEN I.CHG_CORR_FLAG IN ('ORIGINAL', 'REVERSAL') THEN 1
WHEN I.CHG_CORR_REASON != 0 THEN 1
WHEN I.CORR_INV_NUM IS NOT NULL THEN 1
WHEN I.FSC = 5 THEN 1
ELSE 0
END AS CHARGE_CORRECT_F,
E.CHART_KEY,
CPT.PROCEDURE_CODE CPTCODE,
CASE
WHEN T.Component = '1' THEN DIAG1.ICD_9_CM_CODE
WHEN T.Component = '2' THEN DIAG2.ICD_9_CM_CODE
WHEN T.Component = '3' THEN DIAG3.ICD_9_CM_CODE
WHEN T.Component = '4' THEN DIAG4.ICD_9_CM_CODE
END ICD9CODE,
T.DX_NUM,
T.Component AS Diagnosis_Number,
T.Id AS LinkageID

FROM
STG_P_FC_PATIENT P
INNER JOIN STG_P_FC_INVOICE I
ON P.PATIENT = I.PATIENT and i.GROUP_ZZ != 101 -- remove urgent care data
INNER JOIN #tmp T ON T.PATIENT = I.PATIENT
AND T.INVOICE = I.INVOICE
AND T.GROUP_ZZ = I.GROUP_ZZ
INNER JOIN CLAIM C ON C.PATIENT_NBR = I.PATIENT
AND C.GROUP_NBR = I.GROUP_ZZ AND C.INVOICE = I.INVOICE
INNER JOIN ENCOUNTER E ON E.OLD_ENCOUNTER_ID = P.OTH_NUM AND E.OLD_ENCOUNTER_ID >= '20000000'
INNER JOIN STG_P_DN1_CPTCODE CPT ON T.PROC_ZZ = CPT.RECORD_NUMBER
INNER JOIN STG_P_DN36_ICD9 DIAG1 ON I.DX_ONE = DIAG1.RECORD_NUMBER
LEFT JOIN STG_P_DN36_ICD9 DIAG2 ON I.DX_TWO = DIAG2.RECORD_NUMBER
LEFT JOIN STG_P_DN36_ICD9 DIAG3 ON I.DX_THREE = DIAG3.RECORD_NUMBER
LEFT JOIN STG_P_DN36_ICD9 DIAG4 ON I.DX_FOUR = DIAG4.RECORD_NUMBER


WHERE
(I.UPDATE_DT BETWEEN @pdteBeginDate AND @pdteEndDate )
)AA





Vaibhav T

If I cant go back, I want to go fast...
Go to Top of Page

LoztInSpace
Aged Yak Warrior

940 Posts

Posted - 2011-12-06 : 00:32:43
Shame I didn't see this earlier because I had exactly the same problem myself a month or so back so I spotted your same problem right away.
For the record, I discovered that functions are *always* hard-coded to have a cardinality of 1 which can throw the optimiser down the wrong track. It was solved in exactly the same way as you did. I hate using temp tables (that's the query optmiser's job!). Hopefully one of the next versions will work out or allow you to specify a guess as to the cardinality.
That's not to say you're still not missing a few indexes or join conditions.
Go to Top of Page
   

- Advertisement -