2017-11-02 4 views
0

Ich arbeite an einem Dashboard in PHP MySql, wo Benutzer einloggen und Zugriff auf das Dashboard, Benutzer kann Zugriff auf einzelne Abschnitt und einzelnes Land oder mehrere Abschnitte und mehrere Länder.MySql Abfrage Optimierung Ansatz

Ich habe 3 vordefinierte Ansichten erstellt und aus den vordefinierten Ansichten füge ich in die Übersichtstabellen ein und erlaube den Benutzern, auf die Übersichtstabellen zuzugreifen.

das sind meine vordefinierten Ansichten

unit_details

  select 
     sections.section_id, 
     countries.country_id, 
     business_units.unit_id, 
     sections.section_name, 
     countries.country_name, 
     cities.city_name, 
     business_units.unit_name, 
     business_unit_types.unit_type_name, 
     business_unit_categories.unit_category_name 
     from 
     sections, 
     countries, 
     cities, 
     business_units, 
     business_unit_types, 
     business_unit_categories 
     where 
      business_units.section_id=sections.section_id 
     and business_units.country_id=countries.country_id 
     and business_units.city_id=cities.city_id 
     and business_units.unit_type_id=business_unit_types.unit_type_id 
     and business_units.unit_category_id=business_unit_categories.unit_category_id 
     and cities.country_id=countries.country_id; 

transaction_details

  SELECT 
     transactions.business_date, 
     transactions.transaction_datetime, 
     business_unit_product_category_section.section_id, 
     business_units.country_id, 
     transactions.unit_id, 
     transactions.transaction_id, 
     product_category_groups.product_category_group_name, 
     transactions.product_category_id, 
     product_categories.product_category_name, 
     transactions.product_id, 
     products.product_name, 
     transactions.net_sales 
     FROM 
     transactions, 
     business_unit_product_category_section, 
     business_units, 
     products, 
     product_categories, 
     product_category_groups 
     where 
      transactions.unit_id=business_unit_product_category_section.unit_id 
     and transactions.product_category_id=business_unit_product_category_section.product_category_id 
     and transactions.unit_id=business_units.unit_id 
     and business_unit_product_category_section.section_id=business_units.section_id 
     and business_unit_product_category_section.unit_id=business_units.unit_id 
     and transactions.product_id=products.product_id 
     and transactions.product_category_id=products.product_category_id 
     and transactions.product_category_id=product_categories.product_category_id 
     and product_categories.product_category_id=products.product_category_id 
     and product_categories.product_category_group_id=product_category_groups.product_category_group_id; 

letzte Ansicht

  select 
     unit_details.section_name, 
     unit_details.country_name, 
     unit_details.city_name, 
     unit_details.unit_name, 
     unit_details.unit_type_name, 
     unit_details.unit_category_name, 
     transaction_details.business_date, 
     transaction_details.transaction_datetime, 
     transaction_details.section_id, 
     transaction_details.country_id, 
     transaction_details.unit_id, 
     transaction_details.transaction_id, 
     transaction_details.product_category_group_name, 
     transaction_details.product_category_id, 
     transaction_details.product_category_name, 
     transaction_details.product_id, 
     transaction_details.product_name, 
     transaction_details.net_sales 
     from unit_details ud 
     left join transaction_details td on 
     td.section_id=ud.section_id 
     and 
     td.country_id=ud.country_id 
     and 
     td.unit_id=ud.unit_id; 

Dies ist einer meiner zusammenfassenden Tabelle Abfrage die Übersichtstabellen aktualisiert alle 30 Minuten durch eine Batch-Datei die Ausführung der SQL.

  SET @date_today = DATE(NOW()); 
     select 
     final_view.section_name, 
     final_view.country_name, 
     final_view.city_name, 
     final_view.unit_name, 
     final_view.unit_type_name, 
     final_view.unit_category_name, 
     sum(CASE WHEN @date_today = final_view.business_date THEN final_view.net_sales ELSE 0 END) TODAYS_NETSALES, 
     sum(CASE WHEN month(@date_today) = month(final_view.business_date) and final_view.business_date<[email protected]_today THEN final_view.net_sales ELSE 0 END) MTD_NETSALES 
     from final_view 
     group by final_view.section_name,final_view.country_name,final_view.city_name,final_view.unit_name,final_view.unit_category_name; 

das ist mein Schema

  CREATE TABLE business_units (
     id int(11) NOT NULL, 
     unit_id int(11) NOT NULL, 
     unit_name varchar(30) NOT NULL, 
     section_id int(11) NOT NULL, 
     country_id int(11) NOT NULL, 
     city_id int(11) NOT NULL, 
     unit_type_id int(11) NOT NULL, 
     unit_category_id int(11) NOT NULL, 
     created_by varchar(30) NOT NULL, 
     created_datetime datetime NOT NULL, 
     is_active_status int(1) NOT NULL COMMENT '1-active, 0-not active', 
     status_change_datetime datetime NOT NULL 
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 

     CREATE TABLE business_unit_categories (
     unit_category_id int(11) NOT NULL, 
     unit_category_name varchar(30) NOT NULL, 
     created_by varchar(30) NOT NULL, 
     created_datetime datetime NOT NULL, 
     is_active_status int(1) NOT NULL COMMENT '1-active, 0-not active', 
     status_change_datetime datetime NOT NULL 
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 

     CREATE TABLE business_unit_product_category_section (
     id int(11) NOT NULL, 
     unit_id int(11) NOT NULL, 
     product_category_id int(11) NOT NULL, 
     section_id int(11) NOT NULL, 
     created_by varchar(30) NOT NULL, 
     created_datetime datetime NOT NULL 
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 

     CREATE TABLE business_unit_types (
     unit_type_id int(11) NOT NULL, 
     unit_type_name varchar(30) NOT NULL, 
     created_by varchar(30) NOT NULL, 
     created_datetime datetime NOT NULL, 
     is_active_status int(1) NOT NULL COMMENT '1-active, 0-not active', 
     status_change_datetime datetime NOT NULL 
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 


     CREATE TABLE cities (
     city_id int(11) NOT NULL, 
     city_name varchar(30) NOT NULL, 
     country_id int(11) NOT NULL, 
     created_by varchar(30) NOT NULL, 
     created_datetime datetime NOT NULL 
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 


     CREATE TABLE countries (
     country_id int(11) NOT NULL, 
     country_name varchar(30) NOT NULL, 
     created_by varchar(30) NOT NULL, 
     created_datetime datetime NOT NULL 
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 


     CREATE TABLE products (
     id int(11) NOT NULL, 
     product_id varchar(13) NOT NULL, 
     product_name varchar(300) NOT NULL, 
     product_category_id int(11) NOT NULL, 
     created_by varchar(30) NOT NULL, 
     created_datetime datetime NOT NULL 
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 


     CREATE TABLE product_categories (
     product_category_id int(11) NOT NULL, 
     product_category_name varchar(30) NOT NULL, 
     product_category_group_id int(11) NOT NULL, 
     created_by varchar(30) NOT NULL, 
     created_datetime datetime NOT NULL, 
     is_active_status int(1) NOT NULL COMMENT '1-active, 0-not active', 
     status_change_datetime datetime NOT NULL 
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 


     CREATE TABLE product_category_groups (
     product_category_group_id int(11) NOT NULL, 
     product_category_group_name varchar(30) NOT NULL, 
     created_by varchar(30) NOT NULL, 
     created_datetime datetime NOT NULL, 
     is_active_status int(1) NOT NULL COMMENT '1-active, 0-not active', 
     status_change_datetime datetime NOT NULL 
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 

     CREATE TABLE sections (
     section_id int(11) NOT NULL, 
     section_name varchar(30) NOT NULL, 
     created_by varchar(30) NOT NULL, 
     created_datetime datetime NOT NULL, 
     is_active_status int(1) NOT NULL COMMENT '1-active, 0-not active', 
     status_change_datetime datetime NOT NULL 
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 


     CREATE TABLE transactions (
     id int(11) NOT NULL, 
     business_date date NOT NULL, 
     unit_id int(11) NOT NULL, 
     transaction_id int(11) NOT NULL, 
     transaction_datetime datetime NOT NULL, 
     product_category_id int(11) NOT NULL, 
     product_id varchar(13) NOT NULL, 
     net_sales float NOT NULL, 
     net_qty int(11) NOT NULL 
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 

     CREATE TABLE user_permissions (
     id int(11) NOT NULL, 
     user_id varchar(30) NOT NULL, 
     section_id int(11) NOT NULL, 
     country_id int(11) NOT NULL 
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 


     ALTER TABLE business_units 
     ADD PRIMARY KEY (id), 
     ADD UNIQUE KEY unit_id (unit_id,section_id,country_id), 
     ADD KEY unit_id_2 (unit_id,section_id,country_id), 
     ADD KEY city_id (city_id), 
     ADD KEY unit_type_id (unit_type_id), 
     ADD KEY unit_category_id (unit_category_id); 


     ALTER TABLE business_unit_categories 
     ADD PRIMARY KEY (unit_category_id); 


     ALTER TABLE business_unit_product_category_section 
     ADD PRIMARY KEY (id), 
     ADD UNIQUE KEY unit_id (unit_id,product_category_id,section_id), 
     ADD KEY unit_id_2 (unit_id,product_category_id,section_id); 


     ALTER TABLE business_unit_types 
     ADD PRIMARY KEY (unit_type_id); 


     ALTER TABLE cities 
     ADD PRIMARY KEY (city_id), 
     ADD UNIQUE KEY city_id (city_id,country_id), 
     ADD KEY country_id (country_id), 
     ADD KEY city_id_2 (city_id,country_id); 


     ALTER TABLE countries 
     ADD PRIMARY KEY (country_id); 


     ALTER TABLE products 
     ADD PRIMARY KEY (id), 
     ADD KEY product_id (product_id), 
     ADD KEY product_category_id (product_category_id); 


     ALTER TABLE product_categories 
     ADD PRIMARY KEY (product_category_id), 
     ADD UNIQUE KEY product_category_id (product_category_id,product_category_group_id), 
     ADD KEY product_category_group_id (product_category_group_id); 


     ALTER TABLE product_category_groups 
     ADD PRIMARY KEY (product_category_group_id); 


     ALTER TABLE sections 
     ADD PRIMARY KEY (section_id); 


     ALTER TABLE transactions 
     ADD PRIMARY KEY (id), 
     ADD KEY business_date (business_date), 
     ADD KEY unit_id (unit_id), 
     ADD KEY transaction_id (transaction_id), 
     ADD KEY transaction_datetime (transaction_datetime), 
     ADD KEY product_category_id (product_category_id), 
     ADD KEY product_id (product_id), 
     ADD KEY product_id_3 (product_id,product_category_id); 


     ALTER TABLE transactions 
     MODIFY id int(11) NOT NULL AUTO_INCREMENT; 

     ALTER TABLE user_permissions 
     ADD PRIMARY KEY (id), 
     ADD UNIQUE KEY user_id_3 (user_id,section_id,country_id), 
     ADD KEY user_id (user_id), 
     ADD KEY section_id (section_id), 
     ADD KEY country_id (country_id), 
     ADD KEY user_id_2 (user_id,section_id,country_id); 

     ALTER TABLE user_permissions 
     MODIFY id int(11) NOT NULL AUTO_INCREMENT; 

meine Frage ist,

, ob es ratsam ist, vordefinierte Ansichten wie die oben zu erstellen und zu tun, wählt aus vordefinierten Ansicht und Einfügen in Übersichtstabellen?

oder sollte ich die vordefinierten Ansichten und Übersichtstabellen entfernen und den Stapel anhalten und die Übersichtsansicht über die PHP-Seite nur generieren, wenn Benutzer während der Sitzung auf das Dashboard zugreifen?

Der Grund, warum ich die vordefinierten Ansichten erstellt habe, ist, dass die Transaktionstabelle Millionen von Datensätzen enthält und es etwa 10 bis 15 Minuten dauert, um die Übersichtstabellen zu aktualisieren. Wenn der Benutzer auf das Dashboard zugreift, sind die Daten verfügbar und der Benutzer muss nicht warten, bis die Daten angezeigt werden.

Wenn ich die Daten während der Sitzung erzeuge, muss der Benutzer 10 bis 15 Minuten warten, um die Daten zu sehen.

goody rat auf richtige ansatz und auch auf helfen mir, die sql abfrage zu optimieren.

+1

Wir haben damit aufgehört, Anfragen zu schreiben. 1992. Komm. Begleiten Sie uns. – Strawberry

+0

TL; DR bitte ein kurzes reproduzierbares Problem – DanFromGermany

+0

@DanFromGermany, das Problem ist, die Abfrage dauert so viel Zeit, um die Ergebnisse zu geben, wenn ich die Abfrage während der Sitzung ausführen, so derzeit erzeuge ich die Ergebnisse alle 30 Minuten und halten Die Ausgabe ist für den Benutzer bereit, wenn er sich anmeldet. – davidb

Antwort

1
  • Unclutter - Ich stimme mit Erdbeere Textänderungen.
  • Unclutter - Land nicht normalisieren, nur in der Stadt enthalten.
  • Unclutter - brauchen Sie wirklich created_by und created_datetime.
  • Unclutter - Verwenden Sie keine 5-Wort-Tabellennamen.
  • Verwenden Sie JOIN ... ON ... anstelle der alten "Komma Join".
  • Nicht beide INDEX(a) und INDEX(a,b); Ersteres ist überflüssig und unnötig.
  • Ein UNIQUE Index ist ein Index, so INDEX(a,b) ist nicht erforderlich, wenn Sie auch UNIQUE(a,b) haben.

Zurück zu einigen Ihrer Frage ...

  • A VIEW (in MySQL) ist syntaktischer Zucker - es nie schneller als das Äquivalent SELECT sein kann. (Obwohl es einfacher zu lesen ist.)
  • Es gibt keine explizite Unterstützung für Zusammenfassung Tabellen in MySQL (auch mit VIEWs). Die manuelle Implementierung ist jedoch eine gute Idee für die Leistung. Ich sehe manchmal 10-mal Leistungsverbesserung.
+0

danke. Die indexbezogenen Zweifel sind jetzt geklärt, vielen Dank. also werde ich Übersichtstabellen verwenden, so wie es ist, die einzige Änderung, die ich tun muss, ist, anstatt aus Ansichten auszuwählen und in eine Übersichtstabelle einzufügen, direkt aus Tabellen auszuwählen und in Übersichtstabellen einzufügen? – davidb

+0

@davidb - Das ist eine kurze Zusammenfassung der Verwendung der Übersichtstabelle;). Mehr zu Übersichtstabellen: http://mysql.rjweb.org/doc.php/summarytables –

+0

danke, das war ein toller Einblick in Übersichtstabellen. es löscht meine Zweifel. – davidb

2

Keine Antwort. Zu lange für einen Kommentar.

Wir würden normalerweise diese Art von Abfragen auf diese Weise schreiben. Ich schlage vor, Sie hier starten und Ihre Frage ändern (und Ihr Datenmodell möglicherweise) entsprechend ...

SELECT s.section_id 
    , c.country_id 
    , u.unit_id 
    , s.section_name 
    , c.country_name 
    , x.city_name 
    , u.unit_name 
    , t.unit_type_name 
    , y.unit_category_name 
    FROM sections s 
    JOIN business_units u 
    ON u.section_id = s.section_id 
    JOIN countries c 
    ON u.country_id = c.country_id 
    JOIN cities x 
    ON x.city_id = u.city_id 
    AND x.country_id = c.country_id -- there is a redundancy in your model here 
    JOIN business_unit_types t 
    ON t.unit_type_id = u.unit_type_id 
    JOIN business_unit_categories y 
    ON y.unit_category_id u.unit_category_id 
+0

danke, könnten Sie bitte beraten, ob es gut ist, eine vordefinierte Ansichten zu haben? Oder gibt es noch einen anderen guten Ansatz, der schnellere Ergebnisse bringt? – davidb

+0

Ich kann andere RDBMS nicht kommentieren. In MySQL gibt es nur sehr begrenzte Möglichkeiten, Abfragen für Ansichten zu verwenden, um Indizes zu verwenden. Meiner Meinung nach ist die Verwendung von Ansichten daher wenig sinnvoll. – Strawberry

+1

Nachdem Sie JOINS verwendet haben, benutzen Sie 'EXPLAIN' vor der Abfrage, so dass es Ihnen zeigt, wie viele Zeilen es zu untersuchen hat und ob es einen Schlüssel verwendet. Dann können Sie die Reihenfolge Ihrer JOINs ändern und vielleicht 'ORDER BY' und' LIMIT' hinzufügen, um die Dinge zu beschleunigen. Überprüfen Sie auch, ob Ihr Schema vollständig normalisiert ist und ob Sie keine Daten abrufen, die Sie nicht benötigen. Auf diese Weise können Sie eine große Anzahl von Ergebnissen in Millisekunden abfragen. – DanFromGermany