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 undrows × 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
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?
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. –
@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
@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