Mysql
 sql >> Datenbank >  >> RDS >> Mysql

Spalte mit höherer Kardinalität zuerst in einem Index, wenn ein Bereich einbezogen wird?

Lassen Sie uns zuerst FORCE INDEX versuchen um entweder ef auszuwählen oder fe . Die Zeiten sind zu kurz, um ein klares Bild davon zu bekommen, was schneller ist, aber `EXPLAIN zeigt einen Unterschied:

Erzwingen des Bereichs auf filetime Erste. (Hinweis:Die Reihenfolge in WHERE hat keine Auswirkung.)

mysql> EXPLAIN SELECT COUNT(*), AVG(fsize)
    FROM files FORCE INDEX(fe)
    WHERE ext = 'gif' AND filetime >= '2015-01-01'
                      AND filetime <  '2015-01-01' + INTERVAL 1 MONTH;
+----+-------------+-------+-------+---------------+------+---------+------+-------+-----------------------+
| id | select_type | table | type  | possible_keys | key  | key_len | ref  | rows  | Extra                 |
+----+-------------+-------+-------+---------------+------+---------+------+-------+-----------------------+
|  1 | SIMPLE      | files | range | fe            | fe   | 14      | NULL | 16684 | Using index condition |
+----+-------------+-------+-------+---------------+------+---------+------+-------+-----------------------+

ext mit niedriger Kardinalität erzwingen zuerst:

mysql> EXPLAIN SELECT COUNT(*), AVG(fsize)
    FROM files FORCE INDEX(ef)
    WHERE ext = 'gif' AND filetime >= '2015-01-01'
                      AND filetime <  '2015-01-01' + INTERVAL 1 MONTH;
+----+-------------+-------+-------+---------------+------+---------+------+------+-----------------------+
| id | select_type | table | type  | possible_keys | key  | key_len | ref  | rows | Extra                 |
+----+-------------+-------+-------+---------------+------+---------+------+------+-----------------------+
|  1 | SIMPLE      | files | range | ef            | ef   | 14      | NULL |  538 | Using index condition |
+----+-------------+-------+-------+---------------+------+---------+------+------+-----------------------+

Ganz klar die rows sagt ef ist besser. Aber lassen Sie uns mit dem Optimizer-Trace nachsehen. Die Ausgabe ist ziemlich sperrig; Ich zeige nur die interessanten Teile. Kein FORCE wird gebraucht; Der Trace zeigt beide Optionen und wähle dann die bessere aus.

             ...
             "potential_range_indices": [
                ...
                {
                  "index": "fe",
                  "usable": true,
                  "key_parts": [
                    "filetime",
                    "ext",
                    "did",
                    "filename"
                  ]
                },
                {
                  "index": "ef",
                  "usable": true,
                  "key_parts": [
                    "ext",
                    "filetime",
                    "did",
                    "filename"
                  ]
                }
              ],

...

              "analyzing_range_alternatives": {
                "range_scan_alternatives": [
                  {
                    "index": "fe",
                    "ranges": [
                      "2015-01-01 00:00:00 <= filetime < 2015-02-01 00:00:00"
                    ],
                    "index_dives_for_eq_ranges": true,
                    "rowid_ordered": false,
                    "using_mrr": false,
                    "index_only": false,
                    "rows": 16684,
                    "cost": 20022,               <-- Here's the critical number
                    "chosen": true
                  },
                  {
                    "index": "ef",
                    "ranges": [
                      "gif <= ext <= gif AND 2015-01-01 00:00:00 <= filetime < 2015-02-01 00:00:00"
                    ],
                    "index_dives_for_eq_ranges": true,
                    "rowid_ordered": false,
                    "using_mrr": false,
                    "index_only": false,
                    "rows": 538,
                    "cost": 646.61,               <-- Here's the critical number
                    "chosen": true
                  }
                ],

...

          "attached_conditions_computation": [
            {
              "access_type_changed": {
                "table": "`files`",
                "index": "ef",
                "old_type": "ref",
                "new_type": "range",
                "cause": "uses_more_keyparts"   <-- Also interesting
              }
            }

Mit fe (Bereichsspalte zuerst), der Bereich könnte verwendet werden, aber es wird geschätzt, dass 16684 Zeilen durchsucht werden, die nach ext='gif' suchen .

Mit ef (niedrige Kardinalität ext erstens), könnte es beide Spalten des Index verwenden und effizienter im BTree aufschlüsseln. Dann wurden geschätzte 538 Zeilen gefunden, die alle für die Abfrage nützlich sind – keine weitere Filterung erforderlich.

Schlussfolgerungen:

  • INDEX(filetime, ext) nur die erste Spalte verwendet.
  • INDEX(ext, filetime) beide Spalten verwendet.
  • Beteiligte Spalten in = setzen Tests zuerst im Index unabhängig von der Kardinalität .
  • Der Abfrageplan geht nicht über die erste 'range'-Spalte hinaus.
  • "Kardinalität" ist irrelevant für zusammengesetzte Indizes und diese Art von Abfrage .

("Indexbedingung verwenden" bedeutet, dass die Speicher-Engine (InnoDB) Spalten des Index über die zum Filtern verwendete hinaus verwendet.)