2017-11-02 2 views
0

Abfrage-Abfrage mit mehreren Tabellenverbindungen zu viel Zeit trotz der Indizierung

SELECT SUM(sale_data.total_sale) as totalsale, `sale_data_temp`.`customer_type_cy` as `customer_type`, `distributor_list`.`customer_status` FROM `distributor_list` LEFT JOIN `sale_data` ON `sale_data`.`depo_code` = `distributor_list`.`depo_code` and `sale_data`.`customer_code` = `distributor_list`.`customer_code` LEFT JOIN `sale_data_temp` ON `distributor_list`.`address_coordinates` = `sale_data_temp`.`address_coordinates` LEFT JOIN `item_master` ON `sale_data`.`item_code` = `item_master`.`item_code` WHERE `invoice_date` BETWEEN "2017-04-01" and "2017-11-01" AND `item_master`.`id_category` = 1 GROUP BY `distributor_list`.`address_coordinates` 

Query neu geschrieben mit der Formatierung.

SELECT SUM(sale_data.total_sale) as totalsale, 
     sale_data_temp.customer_type_cy as customer_type, 
     distributor_list.customer_status 
    FROM distributor_list 
    LEFT JOIN sale_data 
      ON sale_data.depo_code = distributor_list.depo_code 
      and sale_data.customer_code = distributor_list.customer_code 
    LEFT JOIN sale_data_temp 
      ON distributor_list.address_coordinates = sale_data_temp.address_coordinates 
    LEFT JOIN item_master 
      ON sale_data.item_code = item_master.item_code 
WHERE invoice_date BETWEEN "2017-04-01" and "2017-11-01" 
    AND item_master.id_category = 1 
GROUP BY distributor_list.address_coordinates 

DESC- Diese Abfrage 7,5 Sekunden bis run.My Anwendung nimmt 3-4 enthält solche queries.Therefore Ladezeit appraches 1 min auf dem Server.
Meine Verkaufsdatentabelle enthält 4.5 Lakh (450K) Datensätze.
Die Verteilerliste enthält 970 Datensätze.
Artikelstamm enthält 7774 Datensätze und sale_data_temp enthält 324 Datensätze.
Ich verwende Indizierung, aber es wird nicht für den Verkauf Datentabelle verwendet.
Alle 4 lakh (400K) Datensätze werden gesucht, wie aus explain sql ersichtlich ist.
Wenn ich die Dauer der BETWEEN-Klausel als Verkauf Daten Tabelle reduziert verwendet Datumsindex ansonsten scannt alle 4 Lakh Zeile.
Die Zeilen zwischen 01-04-2017 und 01-11-2017 sind 84000, aber es scannt noch 4 Lakh Zeilen.

MYSQL EXPLAIN- MYSQL EXPLAIN Statement

Ich habe modifizierte fragt zwei Mal ohne Erfolg. Modifikation 1:

SELECT SUM(sale_data.total_sale) as totalsale, `sale_data_temp`.`customer_type_cy` as `customer_type`, `distributor_list`.`customer_status` FROM `distributor_list` LEFT JOIN `sale_data` ON `sale_data`.`depo_code` = `distributor_list`.`depo_code` and `sale_data`.`customer_code` = `distributor_list`.`customer_code` AND `invoice_date` BETWEEN "2017-04-01" and "2017-11-01" LEFT JOIN `sale_data_temp` ON `distributor_list`.`address_coordinates` = `sale_data_temp`.`address_coordinates` LEFT JOIN `item_master` ON `sale_data`.`item_code` = `item_master`.`item_code` WHERE `item_master`.`id_category` = 1 GROUP BY `distributor_list`.`address_coordinates` 

Modifikation 2

SELECT SQL_NO_CACHE SUM(sd.total_sale) AS totalsale, `sale_data_temp`.`customer_type_cy` AS `customer_type` , `distributor_list`.`customer_status` FROM `distributor_list` LEFT JOIN (SELECT * FROM `sale_data` WHERE `invoice_date` BETWEEN "2017-04-01" AND "2017-11-01")sd ON `sd`.`depo_code` = `distributor_list`.`depo_code` AND `sd`.`customer_code` = `distributor_list`.`customer_code` LEFT JOIN `sale_data_temp` ON `distributor_list`.`address_coordinates` = `sale_data_temp`.`address_coordinates` LEFT JOIN `item_master` ON `sd`.`item_code` = `item_master`.`item_code` WHERE `item_master`.`id_category` =1 GROUP BY `distributor_list`.`address_coordinates` 

HIER MEIN INDIZES AUF VERKAUF DATA-Tabelle mysql EXPLAIN AND INDEXES IMAGE

+0

'func' macht es so, als hätten Sie einige Inkonsistenzen in Datentypen und/oder Kollatierungen. –

+1

Helfen Sie uns - formatieren Sie die beiden Auswahlmöglichkeiten und zeigen Sie auf die Unterschiede. –

Antwort

1

Siehe key Spalte der Ansicht EXPLAIN Ergebnisse - es wird kein Schlüssel sein Momentan verwendet MySQL keine Ihrer Indizes zum Herausfiltern von Zeilen, so dass die gesamte Tabelle bei jeder Abfrage durchsucht wird. Deshalb dauert es so lange.

Ich habe mir Ihre erste Abfrage mit Bezug auf Ihre sale_data Indizes angesehen. Es sieht aus wie Sie einen neuen zusammengesetzten Index für diese Tabelle erstellen müssen, die nur die folgenden Spalten enthält:

depo_code, customer_code, item_code, invoice_date, total_sale

Ich empfehle Ihnen, diesen Index zu nennen test1 und experimentieren Sie mit Ändern Sie die Reihenfolge der Spalten und testen Sie jedes Mal erneut, indem Sie EXPLAIN EXTENDED verwenden, bis Sie einen ausgewählten Schlüssel erreichen. Sie möchten, dass in der Spalte key der Index test1 ausgewählt wurde.

Siehe this answer, die mir zuvor mit diesem geholfen hat, und es wird Ihnen helfen, die Bedeutung der korrekten Bestellung Ihrer zusammengesetzten Indizes zu verstehen.

Mit Blick auf die Mächtigkeit der einzelnen Feldindizes, hier ist mein bester Versuch Sie den richtigen Index anwenden zu geben:

ALTER TABLE `sale_data` ADD INDEX `test1` (`item_code`, `customer_code`, `invoice_date`, `depo_code`, `total_sale`); 

Viel Glück mit Ihrer Mission!

+0

Ich habe versucht, dass mehrere Index. Was es tut ist, dass es Test1 und Rechnungsdatum in möglichen Schlüsseln zeigt, aber nicht verwendet. –

+0

Basierend auf dem 'EXPLAIN' sollte 'invoice_date' zuerst in diesem" deckenden "Index stehen - da es das einzige in der' WHERE' Klausel ist. –

+0

Das Hinzufügen von totalsale im Deckungsindex löste das Problem. Die gescannten Zeilen wurden von 400000 auf 92000 reduziert. Aber es dauert immer noch die gleiche Zeit. –

0

Ein paar Dinge zu Ihrer Abfrage zu beachten.

  1. Sie missbrauchen die notorious MySQL extension to GROUP BY. Read this, dann erwähnen Sie die gleichen Spalten in Ihrer GROUP BY Klausel, wie Sie in Ihrer SELECT Klausel erwähnen.

  2. Ihre LEFT JOIN sale_data und LEFT JOIN item_master Operationen sind eigentlich normale JOIN Operationen. Warum? Sie erwähnen Spalten aus diesen Tabellen in Ihrer WHERE-Klausel.

  3. Die beste Option für die Beschleunigung ist das Durchführen eines Datumsbereichscans in einem Index auf sale_data.invoice_date. Aus irgendeinem Grund, der nur den fieberhaften Machenschaften des MySQL-Abfrageplaners bekannt ist, bekommst du es nicht.

Versuchen Sie, Ihre Abfrage zu refactoring. Hier ist ein Vorschlag:

SELECT SUM(sale_data.total_sale) as totalsale, 
     sale_data_temp.customer_type_cy as customer_type, 
     distributor_list.customer_status 
    FROM distributor_list 
    JOIN sale_data 
      ON sale_data.invoice_date BETWEEN "2017-04-01" and "2017-11-01" 
      and sale_data.depo_code = distributor_list.depo_code 
      and sale_data.customer_code = distributor_list.customer_code 
    LEFT JOIN sale_data_temp 
      ON distributor_list.address_coordinates = sale_data_temp.address_coordinates 
    JOIN item_master 
      ON sale_data.item_code = item_master.item_code 
WHERE item_master.id_category = 1 
GROUP BY sale_data_temp.customer_type_cy, distributor_list.customer_status 

Versuchen Sie, einen abdeckenden Index auf sale_data für diese Abfrage zu erstellen. Du musst ein wenig herumspielen, um das richtig zu machen, aber das ist ein Ausgangspunkt. (invoice_date, item_code, depo_code, customer_code, total_sale). Der Punkt eines abdeckenden Indexes ist, dass die Abfrage vollständig aus dem Index erfüllt werden kann, ohne dass auf die Daten der Tabelle zurückgegriffen werden muss. Deshalb habe ich total_sale in den Index aufgenommen.

Bitte beachten Sie, dass der von mir vorgeschlagene Index Ihren Index auf invoice_date überflüssig macht. Sie können diesen Index löschen.

+0

Ich habe den Index verwendet, den Sie erwähnt haben, einschließlich der Gesamtsumme. Die Verkaufsdatenzeilen sind von 400000 auf 92000 gesunken. Aber wenn ich Query in phpmyadmin starte, dauert es trotz reduzierter Verkaufsdatenzeilen in EXPLAIN SQL die gleiche Zeit von 7,5 Sekunden. –

Verwandte Themen