2017-07-17 5 views
0

Ich bin neu in Performance-Tuning in MySQL & brauchen Sie Ihre Hilfe bezüglich einer Ansicht, die später eine Tabelle in unserem Design ersetzen wird.Performance-Probleme mit einer geordneten Ansicht in MySQL

Die Tabelle wird Benutzer und hat folgende Attribute genannt ersetzt: The structure of the TABLE users Die users2 Ansicht hat folgende Attribute: The structure of the VIEW users2

Wenn ich ein normaler auf beiden Objekte SELECT ausführen, sie zur gleichen Zeit reagieren:

SELECT * 
FROM `users` 

SELECT * 
FROM `users2` 

Aber eine geordnete Version dieser Abfragen führen zu einer unterschiedlichen performa nce: Der Tisch ist ein wenig langsamer (dauert weniger als zwei Sekunden), die Ansicht benötigen etwa zehnmal diesmal:

SELECT * 
FROM `users` 
ORDER BY `lastName`, `firstName` 

SELECT * 
FROM `users2` 
ORDER BY `lastName`, `firstName` 

Um den Grund herauszufinden, ich die beiden Kommentare ERKLÄREN lassen: EXPLAIN SELECT * FROM users EXPLAIN SELECT * FROM users2

Offensichtlich ein ALL auf dem Tisch 'ein' (Adressen) auf dem Attribut Countries_ID ist trou machen Ich habe folgendes gemacht:

ALTER TABLE addresses ADD INDEX (Countries_ID); 

Dieser Index hat überhaupt nichts geändert. Also, ich frage Sie nach Ihrer Meinung, was besser gemacht werden kann.

Hinweis 1: Gibt es eine Möglichkeit zum Erstellen eines Index für temporäre Spalte Countries_ID_2? Hinweis 2: Die users2 Ansicht mit der folgenden SQL-Abfrage erstellt wurde:

CREATE OR REPLACE VIEW users2 AS 
(SELECT p.username 
    , p.password 
    , p.firstName 
    , p.lastName 
    , p.eMail AS email 
    , a.settlement AS city 
    , s.name AS country 
    , pl.languages 
    , p.description 
    , p.ID AS ID 
    , p.phone1 
    , p.phone2 
    , CONCAT_WS(' ', a.street, a.addition) AS address 
    , p.status 
    , p.publicMail 
    , ad.name AS Betreuer 
FROM addresses a 
    INNER JOIN addresses_have_persons ap ON a.ID = ap.Addresses_ID 
    INNER JOIN countries c ON a.Countries_ID = c.ID 
    INNER JOIN persons p ON a.ID = p.addressID 
     AND ap.Persons_ID = p.ID 
    INNER JOIN states s ON a.States_ID = s.ID 
    INNER JOIN persons_language pl ON p.ID = pl.ID 
LEFT JOIN advisors ad ON p.advisorID = ad.ID 
-- LEFT JOIN titles t ON t.ID = ad.titleID 
); 

The structure of VIEW users2 Hinweis 3: Obwohl viele Felder in den Personen Tabelle ist NULL, gibt es nicht eine einzige Reihe ist, wo Diese Felder sind insgesamt NULL.

EDIT:

CREATE OR REPLACE VIEW persons_language AS 
(SELECT lp.Persons_ID AS ID 
    , GROUP_CONCAT(DISTINCT l.name ORDER BY l.name SEPARATOR ', ') AS languages 
FROM languages l 
    , languages_have_persons lp 
WHERE l.ID = lp.Languages_ID 
GROUP BY lp.Persons_ID); 

Ohne die ORDER BY werden die Sprachnamen nicht alphabetisch geordnet, die ich zur Zeit möchten. Vielleicht könnten wir uns entscheiden, sie in beliebiger Reihenfolge zu bekommen, aber wir werden sehen.

Derzeit habe ich die folgenden Änderungen ohne Leistungsverbesserung:

ALTER TABLE addresses ADD INDEX (Countries_ID); 
ALTER TABLE addresses ADD INDEX (States_ID); 
ALTER TABLE addresses_have_persons ADD INDEX (Addresses_ID); 
ALTER TABLE languages ADD INDEX (name); 
ALTER TABLE persons ADD INDEX (addressID); 
ALTER TABLE persons ADD INDEX (address2ID); 
ALTER TABLE persons ADD INDEX (address3ID); 
ALTER TABLE persons ADD INDEX (advisorID); 

EDIT 2:

ich dieses Problem diskutieren auch auf einer anderen Website.Die Diskussionen lassen Sie mich es folgende Änderungen tun näher zu sein, in die dritte Normalform:

CREATE OR REPLACE TABLE accounts 
(ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY 
, username VARCHAR(50) NOT NULL UNIQUE 
, password VARCHAR(255) NOT NULL 
, eMail VARCHAR(100) NOT NULL 
, Persons_ID INT NOT NULL 
); 

INSERT INTO accounts (username, password, eMail, Persons_ID) 
SELECT username, password, eMail, ID 
FROM persons; 

Die Tabelle Personen enthält nur das Nötigste und hat die folgende Struktur jetzt: New TABLE persons

die neue Tabelle persons_information trägt alle zusätzlichen Informationen: TABLE persons_information

ich neu erstellt die users2 mit dem folgenden Befehl:

CREATE OR REPLACE VIEW users2 AS 
(SELECT ac.username 
    , ac.password 
    , p.firstName 
    , p.lastName 
    , ac.eMail AS email 
    , adr.settlement AS city 
    , s.name AS country 
    , pl.languages 
    , pi.description 
    , ac.Persons_ID AS ID 
    , pi.phone1 
    , pi.phone2 
    , CONCAT_WS(' ', adr.street, adr.addition) AS address 
    , p.status 
    , pi.publicMail 
    , adv.name AS Betreuer 
FROM accounts ac 
    INNER JOIN persons p ON ac.Persons_ID = p.ID 
    INNER JOIN persons_information pi ON p.ID = pi.ID 
    INNER JOIN addresses adr ON adr.ID = pi.addressID 
    INNER JOIN addresses_have_persons ap ON adr.ID = ap.Addresses_ID 
     AND ap.Persons_ID = p.ID 
    INNER JOIN countries c ON adr.Countries_ID = c.ID 
    INNER JOIN states s ON adr.States_ID = s.ID 
    INNER JOIN persons_language pl ON p.ID = pl.ID 
LEFT JOIN advisors adv ON pi.advisorID = adv.ID 
-- LEFT JOIN titles t ON t.ID = adv.titleID 
); 

Die SELECT _ VON users2 ist schnell, aber wenn ich eine ORDER BY nachName hinzufügen, vorName, dauert es etwa 25 Sekunden, um die Antwort zu erhalten.

Hier sind die Ergebnisse der * EXPLAIN SELECT * FROM users2 * Befehl: EXPLAIN SELECT * FROM users2

Und hier für den anderen Befehl: EXPLAIN SELECT * FROM users2 ORDER BY lastName, firstName

ich auch (wieder) erstellt folgende Indizes:

ALTER TABLE addresses ADD INDEX (Countries_ID); 
ALTER TABLE addresses ADD INDEX (States_ID); 
ALTER TABLE addresses_have_persons ADD INDEX (Persons_ID); 
ALTER TABLE languages ADD INDEX (name); 
ALTER TABLE persons_information ADD INDEX (addressID); 
ALTER TABLE persons_information ADD INDEX (address2ID); 
ALTER TABLE persons_information ADD INDEX (address3ID); 
ALTER TABLE persons_information ADD INDEX (advisorID); 

ich denke, ein Grund für das Problem ist die persons_language Ansicht, die erstellt wird, wie folgt:

CREATE OR REPLACE VIEW persons_language AS 
    (SELECT lp.Persons_ID AS ID 
     , GROUP_CONCAT(DISTINCT l.name ORDER BY l.name SEPARATOR ', ') AS languages 
    FROM languages l 
    INNER JOIN languages_have_persons lp ON l.ID = lp.Languages_ID 
GROUP BY lp.Persons_ID); 

EDIT 3: EXPLAIN SELECT * FROM persons_language

EDIT 4: Für Interessenten, ich die EXPLAIN für die persons_language Ansicht hinzufügen Nach der Datenbank heutigen Sitzung beschlossen wir, alle Objekte löschen in Bezug auf die Adressinformationen & erstellt die Ansicht mit

CREATE OR REPLACE VIEW `users2` AS 
(SELECT ac.username 
    , ac.password 
    , p.firstName 
    , p.lastName 
    , ac.eMail AS email 
    , pl.languages 
    , pi.description 
    , ac.Persons_ID AS ID 
    , pi.phone1 
    , pi.phone2 
    , p.status 
    , pi.publicMail 
    , adv.name AS Betreuer 
FROM accounts ac 
    INNER JOIN persons p ON ac.Persons_ID = p.ID 
    INNER JOIN persons_information pi ON p.ID = pi.ID 
    INNER JOIN persons_language pl ON p.ID = pl.ID 
    INNER JOIN advisors adv ON pi.advisorID = adv.ID 
WHERE ac.password IS NOT NULL 
); 

I erstellt auch einen Index mit

CREATE INDEX LanguagesPersonsIndex ON `languages_have_persons` (`Languages_ID`, `Persons_ID`); 

Dem EXPLAIN Befehl zeigt, dass die neue Indizes in Gebrauch ist, und dass die Verzögerung nach einem SELECT mit einem ORDER BY Klausel mit der neuen, kleineren Ansicht ist, ungefähr 18 s. Hier ist das neue Ergebnis: EXPLAIN SELECT * FROM users2 ORDER BY lastName, firstName Meine Frage ist: Was könnte ich mehr tun, um die Leistung zu verbessern?

Antwort

1

Der Schlüsselfehler muss das Problem sein. Aber abhängig vom Datenvolumen der verbundenen Tabellen, wird es sowieso langsamer sein. Try To:

  • KeyIndexes Implementieren auf alle Attribute verwendet, um Beziehungen festige. (ap.Addresses_ID, a.Countries_ID, p.addressID, ap.Personen_ID, a.States_ID, p.advisorID).
  • PK für alle 'ID' Spalten deklarieren.
  • Verwenden Sie nicht ORDER oder GROUP in der Konstruktion der Ansichten.
  • Schlüsselindex für Attribute deklarieren, die am häufigsten bei Suchen, Ordnen oder Gruppieren verwendet werden.

Tipp: Der 'innere' (INNER JOIN) ist nicht erforderlich. Ist das gleiche von 'JOIN

Ihre VIEW „persons_language“ wäre besser so:

SELECT lp.Persons_ID AS ID, GROUP_CONCAT(DISTINCT l.name ORDER BY l.name SEPARATOR ', ') AS languages 
FROM languages_have_persons lp 
JOIN languages l ON l.ID = lp.Languages_ID 
GROUP BY lp.Persons_ID; 

Es ist besser geeignet, weil die Klauseln ‚VON‘ und ‚nachziehen‘ verarbeitet werden, bevor ‚WHERE‘ Klausel.

Sie können Ihren MySQL-Speicher und Cache-Konfigurationen erhöhen. die Konfigurationen meines MySQL-Server suchen (Führt ein ERP mit Gewichts Tabellen und Views):

join_buffer_size= 256M 
key_buffer = 312M 
key_buffer_size = 768M 
max_allowed_packet = 160M 
thread_stack = 192K 
thread_cache_size = 8 
query_cache_limit = 64M 
innodb_buffer_pool_size = 1512M 
table_cache = 1024M 
read_buffer_size = 4M 
query_cache_size = 768M 
query_cache_limit = 128M 
+0

Vielen Dank für Ihre Antwort, @Renato Tarso! Leider habe ich eine ORDER BY in einer Ansicht, die notwendig ist. Siehe die obige Frage. Alle Auftrags-/Gruppierungs-/Beziehungsattribute sind Schlüssel. – Sae1962

+0

"... sind Primärschlüssel" (Natürlich, keine Primärschlüssel für Ansichten Advisors & Persons_language) – Sae1962

+0

@ Sae1962, überprüfen Sie meine Antwort ändert. Ich hoffe es ist nützlich. Viel Glück. –

0
SELECT * 
FROM `users` 
ORDER BY `lastName`, `firstName` 

Bedürfnisse

INDEX(last_name, first_name) -- in that order 

von VIEWs Vorsicht; einige VIEWs optimieren gut, manche nicht.

Bitte geben Sie SHOW CREATE TABLE für addresses und addresses_have_persons an.

In persons_language, warum brauchen Sie DISTINCT? Hat es nicht PRIMARY KEY(person, language) (oder in umgekehrter Reihenfolge)? Mal sehen SHOW CREATE TABLE.

Bitte geben Sie die EXPLAIN für jede Abfrage, die Sie diskutieren möchten.

Verwandte Themen