2016-07-02 22 views
0

Ich habe folgende Abfrageeine Postgres Abfrage Optimierung

  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 

Und nach der Abfrage-Plan für sie

Query Plan

Wir haben Indizes für folgende Spalten:

  • AccountId
  • createddate
  • Der Status
  • Herkunft

Mit PostgreSQL.

Die Abfrage dauert jedoch lange. Können Sie bitte eine Optimierung vorschlagen?

Dank

+0

Wie viele Zeilen sind in jeder Tabelle? Und ungefähr wie viel von der Tabelle verengt jeder Filter die einzelnen Tabellen? Und wie lange ist eine "lange Zeit"? 20 Sekunden? Eine Minute? 20 Minuten? Eine Stunde? – jpmc26

+1

'CASE WHEN IST NICHT NULL DANN ELSE END' kann ersetzt werden durch 'coalesce (, )' 'um zumindest die Abfrage Notation zu vereinfachen. Oder ich vermisse etwas? – Abelisto

+1

Bitte bearbeiten Sie Ihre Frage und fügen Sie die Ausgabe von 'explain (analyse, verbose)' als _formatted_ text hinzu (oder laden Sie sie auf http: //explain.depesz hoch.com) –

Antwort

3

Ohne viel über Ihren Datensatz zu wissen, und nicht in der Lage den Screenshot des Abfrageplanes zu lesen, sehe ich ein paar einfache Verbesserungen, die Sie machen können.

Erste, um Ihre Nutzung der indizierten Spalten accountId, status und origin Spalten ist in Ordnung. Ihre Verwendung der Spalte createddate ist jedoch fehlerhaft. Wenn Sie die Spalte in eine Zeichenfolge konvertieren und anschließend einen Vergleich durchführen, nachdem sie in eine Zeichenfolge konvertiert wurde, verwenden Sie den Index nicht mehr. Postgres muss einen vollständigen Scan durchführen und zwei kostspielige to_char-Konvertierungen ausführen.

Qualifizieren Sie sich auf Ihrer createddate Spalte mit einem Vergleich, der nativ zum Datentyp der Spalte ist.

Zum Beispiel, wenn der Datentyp von createdatetimestamp ist, dann könnte man auf es wie folgt qualifizieren:

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

Dies wird den Index verwenden, und es wird viel besser ausführen.

Zweite, stellen Sie sicher, dass Sie einen Index erstellt haben, die alle vier der Spalten verwendet, die Sie aufgelistet haben. Wenn Sie vier separate Indizes für jede dieser Spalten erstellt haben, erkennen Sie nicht die vollen Leistungssteigerungen, die durch die Indexierung möglich sind. Ein Index, der alle vier Spalten verwendet, ermöglicht es Postgres, die Ergebnismenge für jede Spalte progressiv einzugrenzen. Wenn Sie vier separate Indizes haben, kann Postgres die Ergebnismenge nur auf eine Spalte eingrenzen.

+0

Der Screenshot ist nun anklickbar und führt zum vollständigen Bild. – melpomene