2016-05-14 7 views
-1

Schaffung ich nicht verstehen kann folgend erklärt:MySQL Probleme mit Tabellendefinition fulltable Scan

Die ersten Grüße nur paziente und ANALISI, es ist in Ordnung, es wird mit Index IDX_NOME

explain 
select 
paziente3_.cognome as col_8_0_ 
from 
Analisi analisi0_ 
inner join 
Paziente paziente3_ 
on analisi0_.ID_PAZIENTE=paziente3_.ID_PAZIENTE 
where 
paziente3_.nome like 'MARCO%'; 


id select_type table  partitions type possible_keys  key     key_len ref         rows filtered Extra 
1 SIMPLE  paziente3_    range PRIMARY,IDX_NOME  IDX_NOME    123           1350 100  Using where; Using index 
1 SIMPLE  analisi0_    ref FK_ANALISI_PAZIENTE FK_ANALISI_PAZIENTE 4  gestelfolab.paziente3_.ID_PAZIENTE 1  100  Using index 

wenn in derselben Abfrage, versuche ich auch SPECIE Beschreibung abzurufen, ist der Index IDX_NOME nicht mehr verwendet und es gibt einen vollständigen Tabellenscan,

explain 
select 
specie5_.specie as col_5_0_, 
paziente3_.cognome as col_8_0_ 
from 
Analisi analisi0_ 
inner join 
Paziente paziente3_ 
on analisi0_.ID_PAZIENTE=paziente3_.ID_PAZIENTE 
inner join 
Specie specie5_ 
on paziente3_.ID_SPECIE=specie5_.ID_SPECIE 
where 
paziente3_.nome like 'MARCO%'; 



id select_type table  partitions type possible_keys      key     key_len ref         rows filtered Extra 
1 SIMPLE  specie5_    index PRIMARY        SPECIE    137           1  100  Using index 
1 SIMPLE  paziente3_    ALL PRIMARY,IDX_NOME,FK_PAZIENTE_SPECIE                 176184 10  Range checked for each record (index map: 0x19) 
1 SIMPLE  analisi0_    ref FK_ANALISI_PAZIENTE     FK_ANALISI_PAZIENTE 4  gestelfolab.paziente3_.ID_PAZIENTE 1  100  Using index 

ist es wegen ein Fehler in der Tabellendefinition?

CREATE TABLE SPECIE 
(
ID_SPECIE TINYINT UNSIGNED NOT NULL AUTO_INCREMENT, 
SPECIE VARCHAR(45) NOT NULL UNIQUE, 
PRIMARY KEY (ID_SPECIE) 
) 
ENGINE=InnoDB; 


Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment 
specie 0   PRIMARY 1    ID_SPECIE A   0         BTREE     
specie 0   SPECIE 1    SPECIE  A   0         BTREE     



CREATE TABLE PAZIENTE 
(
    ID_PAZIENTE   INT   UNSIGNED NOT NULL AUTO_INCREMENT, 
    ID_PAZIENTE_LAB  VARCHAR(20), 
    COGNOME    VARCHAR(40), 
    NOME     VARCHAR(40), 
    DATA_NASCITA   DATE, 
    ID_SESSO    TINYINT UNSIGNED NOT NULL, 
    RECAPITO    VARCHAR(50), 
    CODICE_FISCALE  VARCHAR(30), 
    ID_SPECIE   TINYINT UNSIGNED NOT NULL, 
    PRIMARY KEY (ID_PAZIENTE), 
    INDEX IDX_DATA_NASCITA (DATA_NASCITA, ID_SESSO, ID_SPECIE), 
    INDEX IDX_COGNOME (COGNOME, NOME, ID_SESSO, ID_SPECIE), 
    INDEX IDX_NOME (NOME, COGNOME, ID_SESSO, ID_SPECIE), 
    CONSTRAINT FK_PAZIENTE_SPECIE FOREIGN KEY (ID_SPECIE) REFERENCES SPECIE(ID_SPECIE), 
    CONSTRAINT FK_PAZIENTE_SESSO FOREIGN KEY (ID_SESSO) REFERENCES SESSO(ID_SESSO) 
) 
ENGINE=InnoDB; 




Table  Non_unique Key_name   Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment 
paziente 0   PRIMARY    1    ID_PAZIENTE A   176176        BTREE 
paziente 1   IDX_DATA_NASCITA 1    DATA_NASCITA A   15594       YES BTREE 
paziente 1   IDX_DATA_NASCITA 2    ID_SESSO  A   25007        BTREE 
paziente 1   IDX_DATA_NASCITA 3    ID_SPECIE  A   17922        BTREE 
paziente 1   IDX_COGNOME   1    COGNOME  A   62479       YES BTREE 
paziente 1   IDX_COGNOME   2    NOME   A   163074       YES BTREE 
paziente 1   IDX_COGNOME   3    ID_SESSO  A   170270        BTREE 
paziente 1   IDX_COGNOME   4    ID_SPECIE  A   154908        BTREE 
paziente 1   IDX_NOME   1    NOME   A   55289       YES BTREE 
paziente 1   IDX_NOME   2    COGNOME  A   166062       YES BTREE 
paziente 1   IDX_NOME   3    ID_SESSO  A   176184        BTREE 
paziente 1   IDX_NOME   4    ID_SPECIE  A   176184        BTREE 
paziente 1   FK_PAZIENTE_SPECIE 1    ID_SPECIE  A   1         BTREE 
paziente 1   FK_PAZIENTE_SESSO 1    ID_SESSO  A   1         BTREE 

Wenn ich die neue IDX_NOME erzwingen:

explain 
    select 
    specie5_.specie as col_5_0_, 
    paziente3_.cognome as col_8_0_ 
    from 
    Analisi analisi0_  
    inner join 
    Paziente paziente3_  FORCE INDEX (IDX_NOME) 
    on analisi0_.ID_PAZIENTE=paziente3_.ID_PAZIENTE 
    inner join 
    Specie specie5_ 
    on paziente3_.ID_SPECIE=specie5_.ID_SPECIE 
    where 
    paziente3_.nome like 'MARCO%' 
; 

das Ergebnis ist die folgende:

id select_type table  partitions type possible_keys  key     key_len ref         rows filtered Extra 
1 SIMPLE  specie5_    index PRIMARY    SPECIE    137           1  100  Using index 
1 SIMPLE  paziente3_    range IDX_NOME    IDX_NOME    123           1350 100  Using where; Using index; Using join buffer (Block Nested Loop) 
1 SIMPLE  analisi0_    ref FK_ANALISI_PAZIENTE FK_ANALISI_PAZIENTE 4  gestelfolab.paziente3_.ID_PAZIENTE 1  100  Using index 

Vielleicht können wir sagen, dass die FULL SCAN TABLE ist kein Problem in dieser Fall?

+0

Lernen Sie von Ihren früheren Posts, wie man einen Beitrag formatiert –

+0

a) Bearbeiten Sie Ihre Frage, fügen Sie keine Antwort hinzu. b) Add show index für ALLE relevanten Tabellen (Spezies scheint problematisch) c) Ich schlug einen Index 'IDX_NOME (NOME, ID_SPECIE)' (nicht mehr) oder umgekehrt vor, aber das scheint nicht das Problem zu sein. d) Ihre Statistiken sehen gut aus, aber sie sagen, dass jede 'ID_spezies' den gleichen Wert in' paziente' hat. Ist das korrekt? e) Aus irgendeinem Grund ist mysql der Meinung, dass der direkte Zugriff auf die Arten-Tabelle zu teuer ist. f) Versuch: 1. addiere ';' nach 'wie 'MARCO%';'. 2. Versuchen Sie 'force index ...' wie in meiner Antwort beschrieben. 3. 'ANALYZE TABLE paziente, species' 4. Was ist deine mysql-Version? – Solarflare

+0

Danke nochmal für deine Zeit, – Etantonio

Antwort

0

Wenn Sie Fragen dazu haben, warum mysql einen bestimmten Index verwendet (oder nicht), geben Sie bitte immer die Ausgabe von "show index on tablename" für Ihre Tabelle (n) an. Die dort angegebenen Informationen werden von mysql verwendet, um zu entscheiden, welcher Index verwendet werden soll. Und um zu verstehen, warum mysql einen Index verwendet oder nicht, hilft es, die Informationen zu haben, die mysql verwendet, um zu entscheiden, welcher Index verwendet werden soll oder nicht.

Und diese Informationen könnten veraltet sein, also sollten Sie zuerst eine ANALYZE TABLE ANALISI, PAZIENTE, SPECIE machen und Ihre Erklärung erneut prüfen (sie wird die Tabelle sperren, bis sie fertig ist, nur für den Fall, dass Sie diese auf einem Produktionsserver verwenden) .

Like ist kein starker Indikator für die Verwendung eines bestimmten Index, da es passieren kann, dass Sie eine Abfrage like '%Marco% verwenden. Wenn das passieren kann, können Sie jetzt genauso gut aufhören zu lesen, da Ihr Index im Allgemeinen nicht verwendet werden kann (aber Sie könnten einen Volltextindex ausprobieren).

zu tun, um die join und where Sie Informationen über und NOME in Ihrem PATIENZE -table benötigen. Leider haben Sie keinen Index, der beide Informationen gleichzeitig enthält.

Es ist schwer, ohne den SHOW INDEX -Daten sicher zu wissen, aber das Ergebnis zu erhalten, könnte es eine gute Idee, die specie Informationen Einträge in den FK_PAZIENTE_SPECIE zu sehen, so dass Sie in diesen tatsächlichen aussehen müssen nicht Tabelle; Auf der anderen Seite können Sie den Eintrag IDX_NOME für Einträge mit dem gewünschten Namen einchecken. Dies wird Ihnen 2 Listen geben. Jetzt müssen Sie prüfen, welche Einträge sich in beiden Listen befinden. Denken Sie darüber nach, wie Sie dies tun müssen: Nehmen Sie einen Eintrag der Liste 1 (es enthält den Primärschlüssel) und blättern Sie dann durch die Liste 2, um zu sehen, ob der Primärschlüssel auch dort ist. Dies wird möglicherweise schneller, wenn Sie die Liste 2 zuerst nach dem Primärschlüssel sortieren.

MySQL kann nicht zwei Indizes gleichzeitig für die gleiche Tabelle verwenden (aufgrund dessen, was "einen Index verwenden" bedeutet technisch), aber es kann natürlich eine ähnliche Sache wie oben beschrieben und weiterhin die Indizes zu verwenden Holen Sie sich die erforderlichen Informationen.Das ist was Range checked for each record (index map: 0x19) bedeutet: es kombiniert Informationen aus mehreren Indizes (hier: der 1., 4. und 5. Index in Ihrer SHOW INDEX FROM PAZIENTE -Tabelle, die sein sollte, wenn ich mich nicht irre, PRIMARY, IDX_NOME und FK_PAZIENTE_SPECIE), die jeweils einige enthalten der benötigten Informationen. Da es keine direkte Verbindung zwischen IDX_NOME und FK_PAZIENTE_SPECIE gibt (diese sind indirekt über PRIMARY verbunden), kann das abhängig von Ihren Daten schnell oder langsam sein (es hilft also, wenn die ANALYZE-Informationen aktuell sind, um mysql bei der Entscheidung zu helfen was genau zu tun ist - mysql wird die Strategie nicht ändern, nachdem sie eine gewählt hat, auch wenn es sich während der Ausführung als schlecht herausstellt.

So werden Ihre Indizes tatsächlich verwendet, aber nicht auf die schnellste Weise möglich.

Was kann ich dagegen tun? Wenn Sie bis hierher gefolgt sind, wissen Sie vielleicht bereits: "Um die join und where zu tun, benötigen Sie Informationen über und NOME in Ihrer PATIENZE-Tabelle." Also gib es einfach an mysql: Erstelle einen Index mit beiden Spalten. Es hängt von Ihren Daten ab, welche Reihenfolge besser ist, und wenn Sie Abfragen mit '% MARCO% you should put ID_SPECIE` zuerst verwenden möchten, da andernfalls der Index nicht verwendet werden kann.

Probieren Sie es aus, dies sollte mysql jetzt den neuen Index verwenden. Wenn nicht (und auch kein anderer Index), könnte das eine gute Folgefrage sein, aber bitte fügen Sie dann wirklich die show index -Information hinzu.

Sie können natürlich immer einen Schlüssel durch ... join Paziente paziente3_ force index (idx_PAZIENTE_nome_specie) ... erzwingen und prüfen, ob es wirklich schneller ist oder ob mysql eigentlich richtig war, es nicht zu benutzen. (Aber dann wird es versuchen, diesen Index zu verwenden, auch wenn Sie zB nach '% MARCO%' suchen, was im Grunde genommen gar keinen Index bedeutet, selbst wenn es dann besser ist, FK_PAZIENTE_SPECIE zu verwenden, dann müssen Sie diesen Index hinzufügen auch, und so weiter. verwenden also die Kraft, mit Sorgfalt.)

und es könnte für die Prüfung und Vergleich, wenn ... join Paziente paziente3_ force index (idx_nome) ... jetzt einen Versuch wert sein (bevor Sie einen anderen Index hinzufügen und bevor Sie ANALYZE TABLES tun), den Trick . Auf den ersten Blick würde ich davon ausgehen, dass dies schon schneller sein sollte, aber vielleicht war mysql schon richtig, den Index nicht zu verwenden.