2017-01-08 2 views
0

Die MySQL 5.7 documentation Zustände:Was sagt mir die "gefilterte" Spalte in MySQL EXPLAIN, und wie kann ich sie nutzen?

Die filtered Spalte gibt einen geschätzten Anteil von Tabellenzeilen, die durch den Tabellen Zustand gefiltert wird. Das heißt, rows zeigt die geschätzte Anzahl der geprüften Zeilen und rows × filtered/100 zeigt die Anzahl der Zeilen, die mit vorherigen Tabellen verknüpft werden.

Um zu versuchen, dies besser zu verstehen, habe ich es bei einer Abfrage mit der MySQL Sakila Sample Database ausprobiert. Die betreffende Tabelle hat die folgende Struktur:

mysql> SHOW CREATE TABLE film \G 
*************************** 1. row *************************** 
     Table: film 
Create Table: CREATE TABLE `film` (
    `film_id` smallint(5) unsigned NOT NULL AUTO_INCREMENT, 
    `title` varchar(255) NOT NULL, 
    `description` text, 
    `release_year` year(4) DEFAULT NULL, 
    `language_id` tinyint(3) unsigned NOT NULL, 
    `original_language_id` tinyint(3) unsigned DEFAULT NULL, 
    `rental_duration` tinyint(3) unsigned NOT NULL DEFAULT '3', 
    `rental_rate` decimal(4,2) NOT NULL DEFAULT '4.99', 
    `length` smallint(5) unsigned DEFAULT NULL, 
    `replacement_cost` decimal(5,2) NOT NULL DEFAULT '19.99', 
    `rating` enum('G','PG','PG-13','R','NC-17') DEFAULT 'G', 
    `special_features` set('Trailers','Commentaries','Deleted Scenes','Behind the Scenes') DEFAULT NULL, 
    `last_update` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, 
    PRIMARY KEY (`film_id`), 
    KEY `idx_title` (`title`), 
    KEY `idx_fk_language_id` (`language_id`), 
    KEY `idx_fk_original_language_id` (`original_language_id`), 
    CONSTRAINT `fk_film_language` FOREIGN KEY (`language_id`) REFERENCES `language` (`language_id`) ON UPDATE CASCADE, 
    CONSTRAINT `fk_film_language_original` FOREIGN KEY (`original_language_id`) REFERENCES `language` (`language_id`) ON UPDATE CASCADE 
) ENGINE=InnoDB AUTO_INCREMENT=1001 DEFAULT CHARSET=utf8 

Und dies ist der EXPLAIN Plan für die Abfrage:

mysql> EXPLAIN SELECT * FROM film WHERE release_year=2006 \G 
*************************** 1. row *************************** 
      id: 1 
    select_type: SIMPLE 
     table: film 
    partitions: NULL 
     type: ALL 
possible_keys: NULL 
      key: NULL 
     key_len: NULL 
      ref: NULL 
     rows: 1000 
    filtered: 10.00 
     Extra: Using where 

diese Beispieldatensatz der Tabelle hat 1000 insgesamt Reihen, und alle von ihnen haben release_year Set 2006 die Formel in der Dokumentation von MySQL mit:

rows x filtered/100 = „Anzahl der Zeilen, die mit früheren Tabellen

verbunden werden

So

1,000 x 10/100 = 100 =

Huh "100 Zeilen mit vorherigen Tabellen verknüpft werden"? Was "vorherige Tabelle"? Es gibt keine JOIN, die hier vor sich gehen.

Was ist mit dem ersten Teil des Angebots aus der Dokumentation? "Geschätzter Prozentsatz der Tabellenzeilen, die nach der Tabellenbedingung gefiltert werden." Nun, die Tabelle Bedingung ist release_year = 2006 und alle Datensätze haben diesen Wert, sollte also nicht filtered entweder 0.00 oder 100.00 sein (je nachdem, was sie mit "gefiltert" bedeuten)?

Vielleicht verhält es sich merkwürdig, weil es keinen Index auf release_year gibt? Also habe ich ein:

mysql> CREATE INDEX test ON film(release_year); 

Die filtered Spalte jetzt 100.00 zeigt. Also, sollte es 0.00 nicht gezeigt haben, bevor ich den Index hinzufügte? Hm. Was ist, wenn ich die Hälfte der Tabelle habe release_year 2006 sein, und die andere Hälfte nicht?

mysql> UPDATE film SET release_year=2017 ORDER BY RAND() LIMIT 500; 
Query OK, 500 rows affected (0.03 sec) 
Rows matched: 500 Changed: 500 Warnings: 0 

Nun ist die EXPLAIN sieht wie folgt aus:

mysql> EXPLAIN SELECT * FROM film WHERE release_year=2006 \G 
*************************** 1. row *************************** 
      id: 1 
    select_type: SIMPLE 
     table: film 
    partitions: NULL 
     type: ref 
possible_keys: test 
      key: test 
     key_len: 2 
      ref: const 
     rows: 500 
    filtered: 100.00 
     Extra: Using index condition 

Und da ich mich noch weiter zu verwirren entschieden:

mysql> EXPLAIN SELECT * FROM film WHERE release_year!=2006 \G 
*************************** 1. row *************************** 
      id: 1 
    select_type: SIMPLE 
     table: film 
    partitions: NULL 
     type: ALL 
possible_keys: test 
      key: NULL 
     key_len: NULL 
      ref: NULL 
     rows: 1000 
    filtered: 50.10 
     Extra: Using where 

So wird eine Schätzung von 501 Zeilen gefiltert werden die Tabellenbedingung und "mit vorherigen Tabellen verbunden"?

Ich verstehe einfach nicht.

Ich weiß, es ist eine "Schätzung", aber auf was basiert diese Schätzung?Wenn ein Index vorhanden ist, verschiebt sich der Schätzwert auf 100.00, sollte sein Fehlen nicht 0.00, nicht 10.00 sein? Und was ist damit 50.10 Ergebnis in der letzten Abfrage?

Ist filtered überhaupt nützlich bei der Bestimmung, ob eine Abfrage weiter optimiert werden kann, oder wie es weiter zu optimieren, oder ist es „Rauschen“ in der Regel nur das ignoriert werden kann?

Antwort

0

Sie müssen also eine davon schreiben, um perfekt zu verstehen, aber die Schätzung basiert nicht auf den Inhalten, sondern Metadaten über die Inhalte und Statistiken.

Lassen Sie mich Ihnen ein bestimmtes aus Beispiel ich jede SQL-Plattform nicht sagen, das tut, was ich beschreibe hier das ist nur ein Beispiel:

Sie haben eine Tabelle mit 1000 Zeilen und Maximalwert für das Jahr Spalte ist 2010 und min Wert für Jahr Spalte ist 2000 - ohne weitere Informationen können Sie "raten", dass Jahr = 2007 wird 10% aller Artikel unter der Annahme einer durchschnittlichen Verteilung.

In diesem Fall wäre es zurückgeben 1000 und 10.

Um Ihre letzte Frage filtered könnte nützlich sein, zu antworten, wenn (wie oben dargestellt) nur ein „default“ Wert haben, der alles weg wirft - Sie könnten sich dafür entscheiden, say null anstelle eines Standardwerts zu verwenden, um die Leistung Ihrer Abfragen zu verbessern. Oder Sie sehen, dass Statistiken häufiger in Ihren Tabellen ausgeführt werden müssen, da sich die Bereiche stark ändern. Dies hängt sehr von einer bestimmten Plattform und Ihrem Datenmodell ab.

+0

Ihr Beispiel ist sinnvoll für diese hypothetisch zusammengestellte Datenbank, aber es hilft mir nicht wirklich zu verstehen, wie MySQL es macht oder was es bedeutet. Die Spalte 'release_year' ist nullbar und es gibt keinen Standardwert. Die 1000 Zeilen in dieser Tabelle haben jetzt alle "release_year = 2006", aber ich bekomme immer noch 'filtered: 10.00', unabhängig davon, welchen Wert ich in der Abfrage verwende (2006, 2016,' IS NULL', '= NULL', etc). Die einzige Variation, die ich bekomme, ist, wenn ich '! =' Mache, was zu einem ebenso kryptischen 'filtered: 90.00' führt. –

+0

@MichaelMoussa - Ich kann einen Grund finden, warum es diese Ergebnisse geben würde oder wir könnten uns den Quellcode ansehen, um es herauszufinden. Aber das scheint mir eine nicht nützliche Übung zu sein. – Hogan

+0

@MichaelMoussa - Ich möchte nur überprüfen und sicherstellen - Sie haben 'ANALYZE TABLE' auf diesem Tisch, richtig? (http://dev.mysql.com/doc/refman/5.7/en/analyze-table.html). Wenn Sie nicht haben, basiert das, was es tut, nicht auf einer Analyse des Tabelleninhalts, sondern auf einer Art "Standard" -Wert. – Hogan

Verwandte Themen