sql >> Database >  >> RDS >> Mysql

Kolom met hogere kardinaliteit eerst in een index bij een bereik?

Laten we eerst FORCE INDEX proberen om ef . te kiezen of fe . De timings zijn te kort om een ​​duidelijk beeld te krijgen van wat sneller is, maar `EXPLAIN laat een verschil zien:

Het bereik forceren op filetime eerst. (Opmerking:de volgorde in WHERE heeft geen invloed.)

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 |
+----+-------------+-------+-------+---------------+------+---------+------+-------+-----------------------+

Het forceren van de lage kardinaliteit ext eerst:

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 |
+----+-------------+-------+-------+---------------+------+---------+------+------+-----------------------+

Het is duidelijk dat de rows zegt ef is beter. Maar laten we eens kijken met de Optimizer-tracering. De uitvoer is nogal omvangrijk; Ik laat alleen de interessante delen zien. Geen FORCE is nodig; de trace toont beide opties en kies dan de betere.

             ...
             "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
              }
            }

Met fe (bereikkolom eerst), het bereik zou kunnen worden gebruikt, maar het schatte scannen door 16684 rijen die op ext='gif' vissen .

Met ef (lage kardinaliteit ext eerst), zou het beide kolommen van de index kunnen gebruiken en efficiënter kunnen inzoomen in de Btree. Toen vond het naar schatting 538 rijen, die allemaal nuttig zijn voor de zoekopdracht - geen verdere filtering nodig.

Conclusies:

  • INDEX(filetime, ext) gebruikte alleen de eerste kolom.
  • INDEX(ext, filetime) beide kolommen gebruikt.
  • Plaats kolommen die betrokken zijn bij = test eerst in de index ongeacht de kardinaliteit .
  • Het zoekplan gaat niet verder dan de eerste kolom 'bereik'.
  • 'Kardinaliteit' is niet relevant voor samengestelde indexen en dit type zoekopdracht .

("Indexvoorwaarde gebruiken" betekent dat de Storage Engine (InnoDB) kolommen van de index gebruikt die verder gaan dan degene die voor filteren wordt gebruikt.)




  1. Hoe de ID van de laatst bijgewerkte rij in MySQL te krijgen?

  2. onCreate() van RoomDatabase.Callback() is niet aangeroepen na een succesvolle aanroep van .build()

  3. ORA-27154 / ORA-27146

  4. hoe variabele van shellscript door te geven aan sqlplus