2016-07-22 17 views
0

Ich habe folgende TabellenWie kann ich meinen SQL-Code optimieren?

Kontakte

contact_id | Kontakt_Slug | Kontakt_erster_name | Kontakt_Email | contact_date_added | Firmen-ID | contact_is_active | contact_subscribed | Kontakt_Last_Name | Kontaktfirma | contact_twitter

contact_campaigns

contact_campaign_id | Kontakt-ID | contact_campaign_created | Firmen-ID | contact_campaign_sent

bundle_feedback

bundle_feedback_id | Bündel_ID, Kontakt_ID | Firmen-ID | bundle_feedback_rating | bundle_feedback_favorite_track_id | bundle_feedback_supporting | campaign_id

Bündel

bundle_id | Bündelname | bundle_created | Firmen-ID | bundle_is_active

Spuren

track_id | Firmen-ID | track_title

Ich schrieb diese Abfrage, aber es funktioniert langsam, wie kann ich diese Abfrage optimieren, um es schneller zu machen?

SELECT SQL_CALC_FOUND_ROWS c.contact_id, 
          c.contact_first_name, 
          c.contact_last_name, 
          c.contact_email, 
          c.contact_date_added, 
          c.contact_company, 
          c.contact_twitter, 
          concat(c.contact_first_name," ", c.contact_last_name) AS fullname, 
          c.contact_subscribed, 
          ifnull(icc.sendCampaignsCount, 0) AS sendCampaignsCount, 
          ifnull(round((ibf.countfeedbacks/sendCampaignsCount * 100),2), 0) AS percentFeedback, 
          ifnull(ibf.bundle_feedback_supporting, 0) AS feedbackSupporting 
FROM contacts AS c 
LEFT JOIN 
    (SELECT c.contact_id, 
      count(cc.contact_campaign_id) AS sendCampaignsCount 
    FROM contacts AS c 
    LEFT JOIN contact_campaigns AS cc ON cc.contact_id = c.contact_id 
    WHERE c.company_id = '876' 
    AND c.contact_is_active = '1' 
    AND cc.contact_campaign_sent = '1' 
    GROUP BY c.contact_id) AS icc ON icc.contact_id = c.contact_id 
LEFT JOIN 
    (SELECT bf.contact_id, 
      count(*) AS countfeedbacks, 
      bf.bundle_feedback_supporting 
    FROM bundle_feedback bf 
    JOIN bundles b 
    JOIN contacts c 
    LEFT JOIN tracks t ON bf.bundle_feedback_favorite_track_id = t.track_id 
    WHERE bf.bundle_id = b.bundle_id 
    AND bf.contact_id = c.contact_id 
    AND bf.company_id='876' 
    GROUP BY bf.contact_id) AS ibf ON ibf.contact_id = c.contact_id 
WHERE c.company_id = '876' 
    AND contact_is_active = '1' 
ORDER BY percentFeedback DESC LIMIT 0, 25; 
+0

vermeiden mehrere Tabellen mehrmals verbinden, die auch, wenn es große Anzahl von Datensatz enthält. – Avi

+0

Korrigieren Sie Ihre 'JOIN'-Klauseln, um nach jedem' JOIN' eine 'ON'-Klausel zu haben. Dadurch wird die Leistung nicht verbessert, die Abfrage wird jedoch verständlicher. –

+0

Müssen Sie wirklich SQL-Befehl verbessern? ha ha ha .. nur verbessern Sie Ihre Geschäftslogik und SQL-Abfrage wird deutlich verbessert werden;). – MaNKuR

Antwort

0

Ich habe 2 Verbesserungen gemacht

1) die Kontakte entfernt, die unnötig doppelt verbunden ist, immer und setzen Sie den Zustand in der letzten, wo Zustand.

2) entfernt, wie pro SQL_CALC_FOUND_ROWS

Which is fastest? SELECT SQL_CALC_FOUND_ROWS FROM `table`, or SELECT COUNT(*)

SELECT      c.contact_id, 
          c.contact_first_name, 
          c.contact_last_name, 
          c.contact_email, 
          c.contact_date_added, 
          c.contact_company, 
          c.contact_twitter, 
          concat(c.contact_first_name," ", c.contact_last_name) AS fullname, 
          c.contact_subscribed, 
          ifnull(icc.sendCampaignsCount, 0) AS sendCampaignsCount, 
          ifnull(round((ibf.countfeedbacks/sendCampaignsCount * 100),2), 0) AS percentFeedback, 
          ifnull(ibf.bundle_feedback_supporting, 0) AS feedbackSupporting 
FROM contacts AS c 
LEFT JOIN 
    (SELECT cc.contact_id, 
      count(cc.contact_campaign_id) AS sendCampaignsCount 
    FROM contact_campaigns 
    WHERE cc.contact_campaign_sent = '1' 
    GROUP BY cc.contact_id) AS icc ON icc.contact_id = c.contact_id 
LEFT JOIN 
    (SELECT bf.contact_id, 
      count(*) AS countfeedbacks, 
      bf.bundle_feedback_supporting 
    FROM bundle_feedback bf 
    JOIN bundles b 
    LEFT JOIN tracks t ON bf.bundle_feedback_favorite_track_id = t.track_id 
    WHERE bf.bundle_id = b.bundle_id 
    GROUP BY bf.contact_id) AS ibf ON ibf.contact_id = c.contact_id 
WHERE c.company_id = '876' and c.contact_is_active = '1' 
0

Zuerst Sie identifizieren keine Indizes Sie die Abfrage zu optimieren haben. Das heißt, ich würde sicherstellen, dass Sie mindestens die folgenden zusammengesetzten Indizes haben.

table    index 
contacts   (company_id, contact_is_active) 
contact_campaigns (contact_id, contact_campaign_sent) 
bundle_feedback (contact_id, bundle_feedback_supporting) 

Als nächstes, wie in anderen Antwort erwähnt, es sei denn, Sie wirklich brauchen, wie viele Zeilen qualifiziert, entfernen Sie die „SQL_CALC_FOUND_ROWS“.

In Ihrem ersten linken Join (ICC), machen Sie eine Links-Join auf contact_campaigns (cc), aber werfen Sie dann in Ihre WHERE-Klausel ein "AND cc.contact_campaign_sent = '1'", die daraus ein INNER wird BEITRETEN. Auf der äußeren Abfrageebene würden diese zu keinem übereinstimmenden Datensatz und somit zu NULL für Ihre Prozentberechnungen führen.

In Ihrem zweiten linken Join (ibf) machen Sie einen Join mit der tracks-Tabelle, verwenden aber nichts davon. Sie fügen sich auch der Bundles-Tabelle hinzu, verwenden aber auch nichts von da - es sei denn, Sie erhalten mehrere Zeilen in den Bundles- und Spurtabellen, die zu einem kartesischen Ergebnis führen und möglicherweise Ihren "CountFeedback" -Wert überzeichnen. Sie benötigen auch nicht die Kontakttabelle, da Sie nichts anderes damit tun, und die Feedback-Tabelle hat die Kontakt-ID-Basis, nach der Sie suchen. Da dies nur nach der contact_id gruppiert ist, ist Ihr "bf.bundle_feedback_support" ansonsten verschwendet. Wenn Sie Rückmeldungen erhalten möchten, zählen Sie einfach aus der Tabelle pro Kontakt-ID und entfernen Sie den Rest.(Außerdem sollten die Joins anstelle der WHERE-Klausel die ON-Klauseln haben)

Auch für Ihre unterstützende Rückmeldung sind der Datentyp und der Wert unklar, also habe ich als Ja oder Nein impliziert und habe ein SUM() basierend auf wie viele unterstützen. So kann ein gegebener Kontakt 100 Datensätze haben, aber nur 37 unterstützen. Dies ergibt 1 Datensatz für den Kontakt, der BEIDE Werte 100 bzw. 37 hat und nicht in einer Gruppe verloren geht, basierend auf dem ersten für den Kontakt gefundenen Eintrag.

Ich würde versuchen, Ihre Abfrage unten zusammenfassen:

SELECT 
     c.contact_id, 
     c.contact_first_name, 
     c.contact_last_name, 
     c.contact_email, 
     c.contact_date_added, 
     c.contact_company, 
     c.contact_twitter, 
     concat(c.contact_first_name," ", c.contact_last_name) AS fullname, 
     c.contact_subscribed, 
     ifnull(icc.sendCampaignsCount, 0) AS sendCampaignsCount, 
     ifnull(round((ibf.countfeedbacks/icc.sendCampaignsCount * 100),2), 0) AS percentFeedback, 
     ifnull(ibf.SupportCount, 0) AS feedbackSupporting 
    FROM 
     contacts AS c 

     LEFT JOIN 
     (SELECT 
       c.contact_id, 
       count(*) AS sendCampaignsCount 
       FROM 
       contacts AS c 
        JOIN contact_campaigns AS cc 
         ON c.contact_id = cc.contact_id 
         AND cc.contact_campaign_sent = '1' 
       WHERE 
        c.company_id = '876' 
       AND c.contact_is_active = '1' 
       GROUP BY 
       c.contact_id) AS icc 
      ON c.contact_id = icc.contact_id 

     LEFT JOIN 
     (SELECT 
       bf.contact_id, 
       count(*) AS countfeedbacks, 
       SUM(case when bf.bundle_feedback_supporting = 'Y' 
          then 1 else 0 end) as SupportCount 
       FROM 
       contacts AS c 
        JOIN bundle_feedback bf 
         ON c.contact_id = bf.contact_id 
       WHERE 
        c.company_id = '876' 
       AND c.contact_is_active = '1' 
       GROUP BY 
       bf.contact_id) AS ibf 
      ON c.contact_id = ibf.contact_id 
    WHERE 
      c.company_id = '876' 
     AND c.contact_is_active = '1' 
    ORDER BY 
     percentFeedback DESC LIMIT 0, 25;