0

I have following query

            SELECT
                ca.sfid,
                CASE WHEN p.Name IS NOT NULL THEN p.Name ELSE '' END AS Property,
                CASE WHEN uc.Name IS NOT NULL THEN uc.Name ELSE '' END AS UnitofInterest,
                CASE WHEN fp.Name IS NOT NULL THEN fp.Name ELSE '' END AS FloorplanofInterest,
                CASE WHEN ca.Status IS NOT NULL THEN ca.Status ELSE '' END AS Status,
                CASE WHEN ca.Origin IS NOT NULL THEN ca.Origin ELSE '' END AS Origin,
                CASE 
                    WHEN ca.IC_Call_Answered_by_AH__c = 'true' THEN 'Anyone Home'
                    ELSE 'Property'   
                END AS AnswerBy,
                CASE WHEN ca.CaseNumber IS NOT NULL THEN ca.CaseNumber ELSE '' END AS CaseNumber,
                CASE WHEN ca.Ad_Source_Type__c IS NOT NULL THEN ca.Ad_Source_Type__c ELSE '' END AS Source,
                CONCAT(c.FirstName,' ',c.LastName) AS contactname,
                CASE WHEN (c.Phone IS NOT NULL OR c.Phone != '' ) THEN c.Phone ELSE '' END AS Phone,
                CASE WHEN c.MobilePhone IS NOT NULL THEN c.MobilePhone ELSE '' END AS Mobile,
                CASE WHEN c.Email IS NOT NULL THEN c.Email ELSE '' END AS Email,
                CASE WHEN c.most_recent_military_pay_grade__c IS NOT NULL THEN c.most_recent_military_pay_grade__c ELSE '' END AS MilitaryPayGrade,

                CASE WHEN ca.Price_Quoted_1__c IS NOT NULL THEN ca.Price_Quoted_1__c ELSE '' END AS "price/termquoted",
                CASE WHEN ca.Move_in_Date__c IS NOT NULL THEN to_char(ca.Move_in_Date__c AT TIME ZONE 'US/Pacific', 'MM/DD/YYYY') ELSE '' END AS MoveinDate,
                CASE WHEN ca.Of_Occupants__c::varchar IS NOT NULL THEN ca.Of_Occupants__c::varchar ELSE '' END AS "#occupants",
                CASE WHEN ca.Bed_Count_Pref__c IS NOT NULL THEN ca.Bed_Count_Pref__c ELSE '' END AS BedCountPref,
                CASE WHEN ca.Bath_Count_Pref__c IS NOT NULL THEN ca.Bath_Count_Pref__c ELSE '' END AS BathCountPref,
                CASE WHEN ca.Pet_Count__c::varchar IS NOT NULL THEN ca.Pet_Count__c::varchar ELSE '' END AS "#pets",
                CASE WHEN ca.Pet_Type__c IS NOT NULL THEN ca.Pet_Type__c ELSE '' END AS PetTypes,
                CASE WHEN ca.Breed__c IS NOT NULL THEN ca.Breed__c ELSE '' END AS Breed,
                CASE WHEN ca.Pet_Name__c IS NOT NULL THEN ca.Pet_Name__c ELSE '' END AS PetName,
                CASE 
                    WHEN (ca.Desired_Rent_Start__c IS NOT NULL AND ca.Desired_Rent_Range_End__c IS NOT NULL) THEN CONCAT(ca.Desired_Rent_Start__c,' - ',ca.Desired_Rent_Range_End__c)
                    ELSE '' 
                END AS DesiredRentRange,
                CASE WHEN ca.Desired_Lease_length__c::varchar IS NOT NULL THEN ca.Desired_Lease_length__c::varchar ELSE '' END AS DesiredLeaseLength,
                CASE WHEN ca.Reason_for_Moving__c IS NOT NULL THEN ca.Reason_for_Moving__c ELSE '' END AS ReasonforMoving,
                CASE WHEN ca.Notes__c IS NOT NULL THEN ca.Notes__c ELSE '' END AS Notes,
                CASE WHEN ca.Reasons_For_Not_Setting_a_Showing__c IS NOT NULL THEN ca.Reasons_For_Not_Setting_a_Showing__c ELSE '' END AS ReasonforNotSettingShowing,
                CASE WHEN ca.CreatedDate IS NOT NULL THEN to_char(ca.CreatedDate AT TIME ZONE 'US/Pacific', 'MM/DD/YYYY HH:MI AM') ELSE '' END AS "date/timeopened",
                CASE 
                    WHEN app.appointment_date__c IS NOT NULL THEN  CONCAT(to_char(app.appointment_date__c AT TIME ZONE 'US/Pacific', 'MM/DD/YYYY'),' ',app.from__c,'-',app.to__c)  
                    ELSE '' 
                END AS "appointmentdate/time",
                CASE WHEN ca.Yardi_Guest_Card_ID__c IS NOT NULL THEN ca.Yardi_Guest_Card_ID__c ELSE '' END AS PMSGuestCardID,
                rank() OVER (PARTITION BY ca.contactid, ca.property_of_interest__c ORDER BY ca.createddate DESC)
            FROM
                salesforce.Case ca
                INNER JOIN salesforce.Contact c on ca.ContactId = c.sfid AND c.accountId = ca.accountId
                LEFT JOIN salesforce.Appointment__c app ON ca.sfid = app.case__c
                LEFT JOIN salesforce.Property__c p ON p.sfid = ca.Property_of_Interest__c AND p.account__c = ca.accountId
                LEFT JOIN salesforce.Floor_Plan__c fp ON ca.Floor_Plan_of_Interest__c = fp.sfid AND fp.account__c = ca.accountId
                LEFT JOIN salesforce.Unit__c uc ON ca.Unit_of_Interest__c = uc.sfid AND uc.account__c = ca.accountId

            WHERE
        ca.Guest_Card_Status__c = 'Sent via Workflow'
        AND ca.accountId = '001i000000ESO3CAAX' 
        AND to_char(to_char(ca.createddate AT TIME ZONE 'UTC' AT TIME ZONE 'US/Pacific','YYYY-MM-DD HH24:MI:SS')::date, 'YYYY-MM-DD') BETWEEN  '2016-06-02' AND '2016-07-02' 
        AND to_char(c.Last_Activity__c AT TIME ZONE 'US/Pacific', 'YYYY-MM-DD') BETWEEN  '2016-03-04' AND '2016-07-02' 
        AND ( ca.Status IN ( 'Inquiry', 'Showing Set', 'Showing Completed', 'Application Pending', 'Resident' )  )  
        AND ( ca.IC_Call_Answered_by_AH__c IN ( 'false', 'true' ) )  
        AND ( ca.origin IN ( 'Phone', 'Email', 'Voicemail', 'Chat', 'Walk-In', 'Web' )  OR ca.origin IS NULL OR ca.origin = ''  ) LIMIT 20 OFFSET 0

And following is the query plan for it

Query Plan

We have indexes on following columns:

  • AccountId
  • createddate
  • Status
  • Origin

Using PostgreSQL.

But query is taking long time to run. Can you please suggest any optimization in it?

Thanks

3
  • How many rows are in each table? And roughly how much of the table does each filter narrow each table down to? And how long is a "long time"? 20 seconds? A minute? 20 minutes? An hour? Commented Jul 2, 2016 at 6:36
  • 1
    CASE WHEN <column> IS NOT NULL THEN <column> ELSE <value> END can be replaced by coalesce(<column>, <value>) to simplify at least the query notation. Or I miss something? Commented Jul 2, 2016 at 8:28
  • 1
    Please edit your question and add the output of explain (analyze, verbose) as formatted text (or upload it to explain.depesz.com) Commented Jul 2, 2016 at 8:57

1 Answer 1

3

Without knowing much about your data set and being unable to read the screenshot of the query plan, I see a couple easy improvements you can make.

First, your use of the indexed columns accountId, status, and origin columns is fine. However, your usage of the createddate column is flawed. By converting the column to a string and then performing a comparison after it has been converted to a string, you are no longer using the index -- Postgres must perform a full scan and run two costly to_char conversions.

Qualify on your createddate column with a comparison native to the datatype of the column.

For example, if the datatype of createdate is timestamp, then you could qualify on it like this:

AND ca.createdate BETWEEN '2016-06-02'::timestamp AND '2016-07-02'::timestamp

This will use the index and it will perform much better.

Second, make sure that you've created one index that uses all four of the columns you've listed. If you have created four separate indexes for each of those columns, then you are not realizing the full performance gains possible from indexing. An index that uses all four of the columns will allow Postgres to progressively narrow down the result set with each column. If you have four separate indexes, then Postgres can only narrow down the result set with one column.

Sign up to request clarification or add additional context in comments.

1 Comment

The screenshot is now clickable, leading to the full image.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.