How to tune this query in Oracle 11g - sql

I have been asked to tune the below query and would like to know if there is any better way to tune it?
SELECT req_dtl.lab_ord_occ_test_id ,
req_dtl.order_ref_no ,
req_dtl.accession_no ,
req_dtl.test_code ,
req_dtl.test_name ,
req_dtl.test_id ,
req_dtl.schedule_id ,
req_dtl.lab_ord_occ_id ,
req_dtl.order_type ,
lab_occ.facility_id ,
lab_occ.patient_id ,
lab_occ.order_draw_dt ,
hdr.source_system ,
(SELECT CORPORATION_ACRONYM
FROM corporation c,
facility f
WHERE c.corporation_id = f.corporation_id
AND f.facility_id = lab_occ.facility_id) AS corporation_acronym,
tst.container ,
lab_occ.order_duration_type ,
occ_test.mnc_yn
FROM ORDER_REQUISITION_HEADER hdr ,
ORDER_REQUISITION_DETAIL req_dtl ,
LAB_ORDER_OCC_TEST occ_test ,
LAB_ORDER_OCC lab_occ ,
TEST tst
WHERE hdr.requisition_hdr_id = in_requisition_hdr_id
AND hdr.msg_sent_to_lab_yn = 'Y'
AND req_dtl.requisition_hdr_id = hdr.requisition_hdr_id
AND occ_test.lab_order_occ_test_id = req_dtl.lab_ord_occ_test_id
AND req_dtl.test_id = tst.test_id
AND tst.accession_type NOT LIKE 'CMP%'
AND occ_test.status != 'R'
AND occ_test.lab_order_occ_id = lab_occ.lab_order_occ_id
AND lab_occ.status = 'A'
AND occ_test.created_dt >= hdr.msg_sent_to_lab_dt
AND NVL(occ_test.test_sent_to_lab_yn,'N') = 'N'
AND NOT EXISTS
(SELECT orddata.*
FROM MISSING_ORDER_DATA orddata,
TEST_CONFIG_HOLD_AOE tcha
WHERE orddata.test_id = tcha.test_id
AND tcha.active_yn = 'Y'
AND orddata.status_flag = 'A'
AND orddata.answer IS NULL
AND orddata.msg_sent_to_lab_yn = 'N'
AND orddata.lab_order_occ_test_id=occ_test.lab_order_occ_test_id
)
ORDER BY req_dtl.accession_no;
In the execution plan no tables are going for full table scan.Only nested loops are more.
*Suggest better way to tune this query *

AND NOT EXISTS
(SELECT orddata.*
FROM MISSING_ORDER_DATA orddata,
TEST_CONFIG_HOLD_AOE tcha
WHERE orddata.test_id = tcha.test_id
AND tcha.active_yn = 'Y'
AND orddata.status_flag = 'A'
AND orddata.answer IS NULL
AND orddata.msg_sent_to_lab_yn = 'N'
AND orddata.lab_order_occ_test_id=occ_test.lab_order_occ_test_id
)
could be moved to FROM
FROM
...
LEFT JOIN (SELECT DISTINCT orddata.lab_order_occ_test_id
FROM MISSING_ORDER_DATA orddata,
TEST_CONFIG_HOLD_AOE tcha
WHERE orddata.test_id = tcha.test_id
AND tcha.active_yn = 'Y'
AND orddata.status_flag = 'A'
AND orddata.answer IS NULL
AND orddata.msg_sent_to_lab_yn = 'N'
) missing ON missing.lab_order_occ_test_id = occ_test.lab_order_occ_test_id
WHERE missing.lab_order_occ_test_id IS NULL
Also you should move the acronym
FROM
...
INNER JOIN (SELECT CORPORATION_ACRONYM, f.facility_id
FROM corporation c,
facility f
WHERE c.corporation_id = f.corporation_id) acr ON
acr.facility_id = lab_occ.facility_id)

...Additionally, the TEST object must have an index on accession_type otherwise the tst.accession_type not like 'CMP%' clause will be slower than necessary.
Also, the clause: NVL(occ_test.test_sent_to_lab_yn,'N') = 'N' is essentially an outer join on partially-validated data. Does the test_sent_to_lab_yn column in occ_test contain nulls? If not, consider using an IN clause along with a valid list. [it looks like a yes/no column, maybe this should be equality on 'Y' and get someone to clean up the nulls?]
Please post the explain plan so we can suggest a re-ordering of the predicates in order to minimize the row-returns in first clause....and make HINT suggestions.

Related

Sorry I need to hide

Elon Reeve Musk FRS is an entrepreneur and business magnate. He is the founder, CEO, and Chief Engineer at SpaceX; early-stage investor, CEO, and Product Architect of Tesla, Inc.; founder of The Boring Company; and co-founder of Neuralink and OpenAI.
Your inner select returns a table. That can't be used as parameter to match a WHERE IN condition. Instead try using an INNER JOIN
sum(decode(
select sum(dou.noukn)
from dou
join v_kzeiritsu on
dou.zeiritsu = v_kzeiritsu.zeiritsu
)) as noukn2;
Just move your sum logic inside select as follows:
(SELECT SUM(DOU$2.NOUKN)
FROM SDNISHI.V_KZEIRITSU V
WHERE DOU$2.ZEIRITSU = V.ZEIRITSU) AS NOUKN2
In case If it gives aggregation error then use sum(above query) AS NOUKN2
Your code is very strange. For instance, it seems to assume that V_KZEIRITSU has one row. But, you can move this to the FROM clause:
SELECT SUM(CASE WHEN DOU.ZEIRITSU = K.ZEIRITSU THEN DOU.NOUKN ELSE 0 END) AS NOUKN2
FROM DOU LEFT JOIN
V_KZEIRITSU K
ON 1=1 -- in case the table is really empty
A slightly more reasonable version would be:
SELECT SUM(DOU.NOUKN) AS NOUKN2
FROM DOU LEFT JOIN
V_KZEIRITSU K
ON DOU.ZEIRITSU = K.ZEIRITSU -- in case the table is really empty
It seems rather unlikely to me that this is what you really intend. If not, I would suggest that you ask a new question with appropriate same data, desired results, and explanation of the results. A non-working query should not be expected to provide the same level of information.
I'd say that it is, actually, as simple as
select sum(dou.noukn)
from dou
where dou.zeiritsu in (select zeiritsu from v_kzeiritsu)
(I'm not sure what dou is (table? alias?), but I hope you do.)
After you edited the question, I'm editing the answer. I marked with "--> this" two lines that - in my opinion - might help. As previously, the whole sum(case ...) as noukn2 is replaced by a simple sum(dou$2.noukn).
Note that - in Oracle - you can't use as keyword for table alias. For example:
no: from employees as e
yes: from employees e
Here's your query:
SELECT DOU$2.CUSTCD AS CUSTCD,
DOU$2.CHUNO AS CHUNO,
DOU$2.LINNO AS LINNO,
DOU$2.SHIPDAYYM AS SHIPDAYYM,
SUM (DOU$2.NOUKN) AS NOUKN,
SUM (DOU$2.ZEIKN) AS ZEIKN,
SUM (dou$2.noukn) AS noukn2 --> this
FROM SDNISHI.T_HCHUMON_DOUSOU DOU$2
INNER JOIN SDNISHI.SY_KANRI KNR ON KNR.SHIPDAYYM = DOU$2.SHIPDAYYM
INNER JOIN SDNISHI.T_HCHUMON_MEI MEI
ON MEI.CUSTCD = DOU$2.CUSTCD
AND MEI.CHUNO = DOU$2.CHUNO
AND MEI.LINNO = DOU$2.LINNO
AND MEI.SHIPDAYYM = DOU$2.SHIPDAYYM
AND MEI.USEDNGKBN = '0'
AND MEI.CANCELKBN = '0'
LEFT OUTER JOIN SDNISHI.T_HCHUMON_HD HD
ON HD.CUSTCD = MEI.CUSTCD
AND HD.CHUNO = MEI.CHUNO
AND HD.LINNO = MEI.LINNO
AND HD.USEDNGKBN = '0'
AND HD.CANCELKBN = '0'
AND isnull (HD.CANKBN, '00') = '00'
JOIN v_keziritsu vk ON vk.zeiritsu = dou$2.zeiritsu --> this
WHERE DOU$2.USEDNGKBN = '0'
AND DOU$2.CANCELKBN = '0'
AND ( ( MEI.CHGDELKBN = '1'
AND MEI.HDOUSOUKBN = '02'
AND ( MEI.CHUSU > 0
OR MEI.BCHUSU > 0))
OR ( MEI.CHGDELKBN != '1'
AND HD.HDOUSOUKBN = '02'
AND ( MEI.CHKBTNFGA = '1'
AND HD.CHUSU > 0)
OR ( MEI.CHKBTNFGB = '1'
AND HD.BCHUSU > 0)))
GROUP BY DOU$2.CUSTCD,
DOU$2.CHUNO,
DOU$2.LINNO,
DOU$2.SHIPDAYYM

Using a CASE WHEN statement and an IN (SELECT...FROM) subquery

I'm trying to create a temp table and build out different CASE WHEN logic for two different medications. In short I have two columns of interest for these CASE WHEN statements; procedure_code and ndc_code. There are only 3 procedure codes that I need, but there are about 20 different ndc codes. I created a temp.ndcdrug1 temp table with these ndc codes for medication1 and temp.ndcdrug2 for the ndc codes for medication2 instead of listing out each ndc code individually. My query looks like this:
CREATE TABLE temp.flags AS
SELECT DISTINCT a.userid,
CASE WHEN (procedure_code = 'J7170' OR ndc_code in (select ndc_code from temp.ndcdrug1)) THEN 'Y' ELSE 'N' END AS Drug1,
CASE WHEN (procedure_code = 'J7205' OR procedure_code = 'C9136' OR ndc_code in (select ndc_code from temp.ndcdrug2)) THEN 'Y' ELSE 'N' END AS Drug2,
CASE WHEN (procedure_code = 'J7170' AND procedure_code = 'J7205') THEN 'Y' ELSE 'N' END AS Both
FROM table1 a
LEFT JOIN table2 b
ON a.userid = b.userid
WHERE...
AND...
When I run this, it returns: org.apache.spark.sql.AnalysisException: IN/EXISTS predicate sub-queries can only be used in a Filter.
I could list these ndc_code values out individually, but there are a lot of them so wanted a more efficient way of going about this. Is there a way to use a sub select query like this when writing out CASE WHEN's?
Query.
CREATE TABLE temp.flags AS
SELECT DISTINCT a.userid,
CASE WHEN (
procedure_code = 'J7170' OR
(select min('1') from temp.ndcdrug1 m where m.ndc_code = a.ndc_code) = '1'
) THEN 'Y' ELSE 'N' END AS Drug1,
CASE WHEN (
procedure_code = 'J7205' OR
procedure_code = 'C9136' OR
(select min('1') from temp.ndcdrug2 m where m.ndc_code = a.ndc_code) = '1'
) THEN 'Y' ELSE 'N' END AS Drug2,
CASE WHEN (procedure_code = 'J7170' AND procedure_code = 'J7205')
THEN 'Y' ELSE 'N' END AS Both
FROM table1 a
LEFT JOIN table2 b
ON a.userid = b.userid
WHERE...
AND...

Query Optimization for if exists sub query

I am trying to optimize the query below
if exists (select 1
from GHUB_DISCREPANCY_REPORT (NOLOCK)
where PARTNO = #currentpn and orderID = #oldorderid + 1
and (Discr_Fox_Available = 'Y'
or Discr_Fox_NC = 'Y' or Discr_FOC_Available = 'Y'
or Discr_FOC_NC = 'Y' or Discr_Cpa_Available = 'Y'
or Discr_Cpa_NC = 'Y' or Discr_Fox_Tot = 'Y'
or Discr_FOC_Tot = 'Y' or Discr_Cpa_Tot = 'Y'))
I indexed the primary key, PartNo, Aging and OrderID columns.
Is there any other way I can optimize this query ?
Please suggest!
First, try an index on GHUB_DISCREPANCY_REPORT(PARTNO, orderId). This may be a big help for you query.
If you still have performance problems, one method is to use to separate queries, each of which can be optimized with a separate index.
if exists (select 1
from GHUB_DISCREPANCY_REPORT (NOLOCK)
where PARTNO = #currentpn and orderID = #oldorderid and Discr_Fox_Available = 'Y'
) or
. . .
And then having a separate composite index for each combination: GHUB_DISCREPANCY_REPORT(PARTNO, orderId, Discr_Fox_Available). This is a lot of index overhead, but could be worth it.
Another idea is to combine all the flags into one:
alter table GHUB_DISCREPANCY_REPORT
add Any_Flags as (case when (Discr_Fox_Available = 'Y'
or Discr_Fox_NC = 'Y' or Discr_FOC_Available = 'Y'
or Discr_FOC_NC = 'Y' or Discr_Cpa_Available = 'Y'
or Discr_Cpa_NC = 'Y' or Discr_Fox_Tot = 'Y'
or Discr_FOC_Tot = 'Y' or Discr_Cpa_Tot = 'Y' then 'Y' else 'N' end);
You can add an index on a computed column and then use the value in your query:
create index idx_GHUB_DISCREPANCY_REPORT_anyflags on GHUB_DISCREPANCY_REPORT(PARTNO, OrderId, AnyFlags);
if exists (select 1
from GHUB_DISCREPANCY_REPORT (NOLOCK)
where PARTNO = #currentpn and orderID = #oldorderid and AnyFlags = 'Y'
)
"top 1 1 from tbl_name" gives much better performance than " select 1" in the "if exists" (sub query) part.
Refer to this discussion
After using "top 1 1" estimated number of rows is reduce to 1 from 135765 in my case.

Oracle SubQuery (Display subquery columns)

I cannot seem to find via searching how I would be able to return some of the columns from the the below sub queries. Specifically B.TAP_STAT_HSL/C.TAP_STAT_HSL. I'm not sure if I should be joining instead, but any help would be greatly appreciated.
SELECT
A.HSE_KEY_HSE AS HOUSEKEY,
A.DROP_STAT_HSE AS DROPSTATUS
A.TAP_STAT_HSL AS ITAPSTAT
FROM OPS$SEA.HSE_BASE,OPS$SEA.HSL_LOB,OPS$SEA.OOR_ORDER_OPEN A
WHERE A.HSE_KEY_HSE = A.HSE_KEY_HSL
AND A.HSE_KEY_HSL = A.HSE_KEY_OOR
AND A.DROP_STAT_HSE = '1'
AND A.LOB_IND_HSL = 'I'
AND A.TAP_STAT_HSL IN ('0','2')
AND A.ORD_STAT_OOR <> 'O'
AND EXISTS (SELECT 1
FROM OPS$SEA.HSE_BASE B,OPS$SEA.HSL_LOB B, OPS$SEA.OOR_ORDER_OPEN B
WHERE A.HSE_KEY_HSE = B.HSE_KEY_HSE
AND B.HSE_KEY_HSE = B.HSE_KEY_HSL
AND B.HSE_KEY_HSL = B.HSE_KEY_OOR
AND B.DROP_STAT_HSE = '1'
AND B.LOB_IND_HSL = 'C'
AND B.TAP_STAT_HSL IN ('0','2')
AND B.ORD_STAT_OOR <> 'O')
AND EXISTS (
SELECT 1
FROM OPS$SEA.HSE_BASE C,OPS$SEA.HSL_LOB C, OPS$SEA.OOR_ORDER_OPEN C
WHERE A.HSE_KEY_HSE = C.HSE_KEY_HSE
AND C.HSE_KEY_HSE = C.HSE_KEY_HSL
AND C.HSE_KEY_HSL = C.HSE_KEY_OOR
AND C.DROP_STAT_HSE = '1'
AND C.LOB_IND_HSL = 'T'
AND C.TAP_STAT_HSL IN ('0','2')
AND C.ORD_STAT_OOR <> 'O')}
Hmmm....
I believe your query can be re-written as follows:
WITH Allowed_Rows (houseKey, dropStatus, ipApStat, indicator)
as (SELECT a.HSE_KEY_HSE, a.DROP_STAT_HSE,
b.TAP_STAT_HSL, b.LOB_IND_HSL
FROM OPS$SEA.HSE_BASE as a
JOIN OPS$SEA.HSL_LOB as b
ON b.HSE_KEY_HSL = a.HSE_KEY_HSE
AND b.LOB_IND_HSL IN ('I', 'C', 'T')
AND b.TAB_STAT_HSL IN ('0', '2')
JOIN OPS$SEA.OOR_Order_Open as c
ON c.HSE_KEY_OOR = a.HSE_KEY_HSE
AND c.ORD_STAT_OOR <> '0'
WHERE a.DROP_STAT_HSE = '1')
SELECT houseKey, dropStatus, ipApStat
FROM Allowed_Rows as a
WHERE a.indicator = 'I'
AND EXISTS (SELECT '1'
FROM Allowed_Rows as b
WHERE b.houseKey = a.houseKey
AND b.indicator = 'C')
AND EXISTS (SELECT '1'
FROM Allowed_Rows as b
WHERE b.houseKey = a.houseKey
AND b.indicator = 'T')
You didn't properly qualify some of your tables, and used the same alias for multiple tables (which I'm surprised didn't generate a syntax error), so I had to make my best guess as to where things actually belong. There are a couple of other variations possible, depending on the other (unlisted) requirements and constraints.
And why and how do you need to return the 'other' values of TAP_STAT_HSL? DO you need all possible combinations? The value of the row for B or C instead of A? What?

SQL SP runs Slow

Hi
I am using an SP which takes 7 minutes in a server which has 7336 recrds
and 6seconds in another server which has 3500 records.
Can anybody help me to know why is it happening?
Thanks,
-Divya
THE SP:
SELECT WORKSHEET_ID
FROM PERSON PER
INNER JOIN PERSON EMPLEE
ON EMPLEE.PERSON_ID = PER.PERSON_ID
AND
dbo.FN_CHECKRPTSECURITY(EMPLEE.PERSON_ID, #p_SEC_ACCOUNT_ID) > 0
LEFT JOIN SEARCH_ASSIGNMENT_VW PERSON_ASGN
ON PERSON_ASGN.ASSIGNMENT_ID =
dbo.FN_GETRPTASSIGNMENTID(EMPLEE.PERSON_ID)
LEFT JOIN LOOKUP EMPLEE_ASGN_STAT
ON EMPLEE_ASGN_STAT.TYPE_ = 'ASSIGNMMENT_STATUS_CODE'
AND EMPLEE_ASGN_STAT.CODE = PERSON_ASGN.ASGN_STAT_CODE
INNER JOIN
(SELECT w1.ASSIGNMENT_ID, w1.WORKSHEET_ID, w1.EFFECTIVE_DATE, w1.APPROVED_BY, w3.CREATED_BY
FROM WORKSHEET_PAYROLL_VW w1
INNER JOIN WORKSHEET w3
ON w3.WORKSHEET_ID = w1.WORKSHEET_ID
WHERE w1.EFFECTIVE_DATE = CASE
WHEN #p_MOST_RECENT_ONLY = 'Y'
THEN (SELECT MAX(w2.EFFECTIVE_DATE)
FROM WORKSHEET_PAYROLL_VW w2
WHERE w1.ASSIGNMENT_ID = w2.ASSIGNMENT_ID
AND (ISNULL(#p_WKS_EFFECTIVE_DATE,w2.EFFECTIVE_DATE) =w2.EFFECTIVE_DATE))
ELSE ISNULL(#p_WKS_EFFECTIVE_DATE,w1.EFFECTIVE_DATE)
END
)
PERSON_WKS
ON PERSON_WKS.ASSIGNMENT_ID = dbo.FN_GETRPTASSIGNMENTID(EMPLEE.PERSON_ID)
INNER JOIN
(SELECT ASSIGNMENT_ID, VALUE
FROM ASSIGNMENT_HISTORY AH
WHERE FIELD_NAME ='HOME PAYROLL GROUP'
AND EFFECTIVE_DATE = (SELECT MAX(EFFECTIVE_DATE)
FROM ASSIGNMENT_HISTORY
WHERE ASSIGNMENT_ID = AH.ASSIGNMENT_ID
AND EFFECTIVE_DATE <=getDate()
AND FIELD_NAME = 'HOME PAYROLL GROUP')
)HOME_PAYROLL
ON HOME_PAYROLL.ASSIGNMENT_ID = dbo.FN_GETRPTASSIGNMENTID(EMPLEE.PERSON_ID)
WHERE
(#p_SELECTED_PERSON_ONLY = 'N' OR EMPLEE.PERSON_ID = #p_PERSON_ID)
AND
(#p_ASGN_STAT_CODE IS NULL OR PERSON_ASGN.ASGN_STAT_CODE = SUBSTRING(#p_ASGN_STAT_CODE,1,1)
OR PERSON_ASGN.ASGN_STAT_CODE = SUBSTRING(#p_ASGN_STAT_CODE,2,1))
AND
(#p_POLICY_ID IS NULL OR PERSON_ASGN.PROGRAM_CODE = #p_POLICY_ID)
AND
(#p_HOME_COUNTRY_ID IS NULL OR PERSON_ASGN.HOMECOUNTRYID=#p_HOME_COUNTRY_ID)
AND
(#p_HOME_CITY_ID IS NULL OR PERSON_ASGN.HOMECITYID=#p_HOME_CITY_ID )
AND
(#p_HOME_COMPANY_ID IS NULL OR PERSON_ASGN.HOMEBUSINESSID=#p_HOME_COMPANY_ID )
AND
(#p_HOME_DIVISION_ID IS NULL OR PERSON_ASGN.HOMECOMPONENTID=#p_HOME_DIVISION_ID )
AND
(#p_HOST_COUNTRY_ID IS NULL OR PERSON_ASGN.HOSTCOUNTRYID=#p_HOST_COUNTRY_ID )
AND
(#p_HOST_CITY_ID IS NULL OR PERSON_ASGN.HOSTCITYID=#p_HOST_CITY_ID )
AND
(#p_HOST_COMPANY_ID IS NULL OR PERSON_ASGN.HOSTBUSINESSID=#p_HOST_COMPANY_ID )
AND
(#p_HOST_DIVISION_ID IS NULL OR PERSON_ASGN.HOSTCOMPONENTID=#p_HOST_DIVISION_ID )
AND
(#p_CREATED_BY IS NULL OR PERSON_WKS.CREATED_BY=#p_CREATED_BY )
AND
(#p_APPROVED_BY IS NULL OR PERSON_WKS.APPROVED_BY=#p_APPROVED_BY )
AND
(#p_payroll_code IS NULL OR HOME_PAYROLL.VALUE=#p_payroll_code )
ORDER BY PER.LAST_NAME ASC,
PER.FIRST_NAME ASC,
PERSON_WKS.EFFECTIVE_DATE DESC
The Function in the 5th line is the one which is running slow. rest of the part is running in 4secs
The FUNCTION:
BEGIN
DECLARE
#v_ASGN_COUNT INT,
#v_RESULT INT
SELECT #v_ASGN_COUNT = COUNT(ASSIGNMENT_ID) --to find out if this employee has any assignment
FROM ASSIGNMENT
WHERE EXPATRIATE_PERSON_ID = #p_PERSON_ID AND
ASGN_STAT_CODE IN ('PD','A','I')
IF(#v_ASGN_COUNT > 0) --yes assignment, check against SECURITY_ASSIGNMENT_VW
BEGIN
SELECT #v_RESULT = COUNT(ASSIGNMENT_ID)
FROM SECURITY_ASSIGNMENT_VW
WHERE SEC_ACCOUNT_ID = #p_SEC_ACCOUNT_ID AND
ASSIGNMENT_ID IN (SELECT ASSIGNMENT_ID
FROM ASSIGNMENT
WHERE EXPATRIATE_PERSON_ID = #p_PERSON_ID AND
ASGN_STAT_CODE IN ('PD','A','I'))
END
ELSE --no assignment, so check against SECURITY_PERSON_VW
BEGIN
SELECT #v_RESULT = COUNT(PERSON_ID)
FROM SECURITY_PERSON_VW
WHERE SEC_ACCOUNT_ID = #p_SEC_ACCOUNT_ID AND
PERSON_ID = #p_PERSON_ID
END
RETURN #v_RESULT
END
Do the schemas match exactly... in particular check for missing indexes.
Well to begin with you have scalar functions which will run significantly slower as the number of records increase becasue they process row-by-agonizing-row. Not only that you've used the functions in joins which is a horrible practice if you need performance. You have a bunch of OR conditions which tend to slowness. And while it is too hard to actually read the code you posted (please try to format and only use all caps for keywords), I would suspect that some of those conditions are not sargable.
To know what is actually happening check the Execution plan (SQL Server) or Explain Plan (mySQL and others I think) or the equivalent feature in your database. Likely you wil find table scans which of course are going to get significantly slower as the number of records increases.
You may also have a problem with parameter sniffing. Please google to see how to fix that.
One improvement would be to make sure that dbo.FN_GETRPTSSIGNMENTID only gets executed once.
Currently, it gets executed three times.
You can replace two of those calls by joining to the field of the (one) remaing call.
Something like
SELECT WORKSHEET_ID
FROM PERSON PER
INNER JOIN PERSON EMPLEE ON EMPLEE.PERSON_ID = PER.PERSON_ID AND dbo.FN_CHECKRPTSECURITY(EMPLEE.PERSON_ID, #p_SEC_ACCOUNT_ID) > 0
INNER JOIN (
SELECT w1.ASSIGNMENT_ID
, w1.WORKSHEET_ID
, w1.EFFECTIVE_DATE
, w1.APPROVED_BY
, w3.CREATED_BY
FROM WORKSHEET_PAYROLL_VW w1
INNER JOIN WORKSHEET w3 ON w3.WORKSHEET_ID = w1.WORKSHEET_ID
WHERE w1.EFFECTIVE_DATE =
CASE WHEN #p_MOST_RECENT_ONLY = 'Y'
THEN (
SELECT MAX(w2.EFFECTIVE_DATE)
FROM WORKSHEET_PAYROLL_VW w2
WHERE w1.ASSIGNMENT_ID = w2.ASSIGNMENT_ID AND (ISNULL(#p_WKS_EFFECTIVE_DATE,w2.EFFECTIVE_DATE) = w2.EFFECTIVE_DATE)
)
ELSE ISNULL(#p_WKS_EFFECTIVE_DATE,w1.EFFECTIVE_DATE)
END
) PERSON_WKS ON PERSON_WKS.ASSIGNMENT_ID = dbo.FN_GETRPTASSIGNMENTID(EMPLEE.PERSON_ID)
INNER JOIN (
SELECT ASSIGNMENT_ID
, VALUE
FROM ASSIGNMENT_HISTORY AH
WHERE FIELD_NAME ='HOME PAYROLL GROUP'
AND EFFECTIVE_DATE = (
SELECT MAX(EFFECTIVE_DATE)
FROM ASSIGNMENT_HISTORY
WHERE ASSIGNMENT_ID = AH.ASSIGNMENT_ID
AND EFFECTIVE_DATE <=getDate()
AND FIELD_NAME = 'HOME PAYROLL GROUP'
)
LEFT JOIN SEARCH_ASSIGNMENT_VW PERSON_ASGN ON PERSON_ASGN.ASSIGNMENT_ID = PERSON_WKS.ASSIGNMENT_ID
LEFT JOIN LOOKUP EMPLEE_ASGN_STAT ON EMPLEE_ASGN_STAT.TYPE_ = 'ASSIGNMMENT_STATUS_CODE' AND EMPLEE_ASGN_STAT.CODE = PERSON_ASGN.ASGN_STAT_CODE
) HOME_PAYROLL ON HOME_PAYROLL.ASSIGNMENT_ID = PERSON_WKS.ASSIGNMENT_ID
WHERE (#p_SELECTED_PERSON_ONLY = 'N' OR EMPLEE.PERSON_ID = #p_PERSON_ID)
AND (#p_ASGN_STAT_CODE IS NULL OR PERSON_ASGN.ASGN_STAT_CODE = SUBSTRING(#p_ASGN_STAT_CODE,1,1) OR PERSON_ASGN.ASGN_STAT_CODE = SUBSTRING(#p_ASGN_STAT_CODE,2,1))
AND (#p_POLICY_ID IS NULL OR PERSON_ASGN.PROGRAM_CODE = #p_POLICY_ID)
AND (#p_HOME_COUNTRY_ID IS NULL OR PERSON_ASGN.HOMECOUNTRYID=#p_HOME_COUNTRY_ID)
AND (#p_HOME_CITY_ID IS NULL OR PERSON_ASGN.HOMECITYID=#p_HOME_CITY_ID )
AND (#p_HOME_COMPANY_ID IS NULL OR PERSON_ASGN.HOMEBUSINESSID=#p_HOME_COMPANY_ID )
AND (#p_HOME_DIVISION_ID IS NULL OR PERSON_ASGN.HOMECOMPONENTID=#p_HOME_DIVISION_ID )
AND (#p_HOST_COUNTRY_ID IS NULL OR PERSON_ASGN.HOSTCOUNTRYID=#p_HOST_COUNTRY_ID )
AND (#p_HOST_CITY_ID IS NULL OR PERSON_ASGN.HOSTCITYID=#p_HOST_CITY_ID )
AND (#p_HOST_COMPANY_ID IS NULL OR PERSON_ASGN.HOSTBUSINESSID=#p_HOST_COMPANY_ID )
AND (#p_HOST_DIVISION_ID IS NULL OR PERSON_ASGN.HOSTCOMPONENTID=#p_HOST_DIVISION_ID )
AND (#p_CREATED_BY IS NULL OR PERSON_WKS.CREATED_BY=#p_CREATED_BY )
AND (#p_APPROVED_BY IS NULL OR PERSON_WKS.APPROVED_BY=#p_APPROVED_BY )
AND (#p_payroll_code IS NULL OR HOME_PAYROLL.VALUE=#p_payroll_code )
ORDER BY
PER.LAST_NAME ASC
, PER.FIRST_NAME ASC
, PERSON_WKS.EFFECTIVE_DATE DESC