J'ai lu à propos de composite indexes
et je suis un peu confus au sujet de la commande. Cette documentation (un peu moins qu'à mi-chemin) dit
En général, vous devez d'abord placer la colonne devant être utilisée le plus souvent dans l'index.
Cependant, peu de temps après
créer un index composite mettant la colonne la plus sélective en premier; c'est-à-dire la colonne avec le plus de valeurs.
Oracle le dit aussi ici en d'autres termes
Si toutes les clés sont utilisées dans les clauses WHERE de la même manière, le classement de ces clés de la plus sélective à la moins sélective dans l'instruction CREATE INDEX améliore au mieux les performances de la requête.
Cependant, j'ai trouvé un réponse SO qui dit différemment. Ça dit
Disposez les colonnes avec la colonne la moins sélective en premier et la colonne la plus sélective en dernier. Dans le cas d'un lien avec la colonne qui est plus susceptible d'être utilisé seul.
La première documentation que j'ai référencée dit que vous devez d'abord passer par la plus utilisée alors que la réponse SO dit que cela ne devrait être que pour le bris d'égalité. Ensuite, ils diffèrent également sur la commande.
Cette documentation parle également de skip scanning
et dit
Le saut de balayage est avantageux s'il y a peu de valeurs distinctes dans la colonne de tête de l'index composite et de nombreuses valeurs distinctes dans la clé non leader de l'index.
Un autre article dit
La colonne de préfixe doit être la plus discriminante et la plus utilisée dans les requêtes
qui, selon moi, est le plus discriminant et le plus distinctif.
Toutes ces recherches m'amènent toujours à la même question; La colonne la plus sélective doit-elle être la première ou la dernière? La première colonne doit-elle être la plus utilisée et la plus sélective lors d'un bris d'égalité?
Ces articles semblent se contredire, mais ils offrent quelques exemples. D'après ce que j'ai rassemblé, il semble être plus efficace pour le least selective column
être le premier dans le classement si vous prévoyez Index Skip Scans
. Mais je ne suis pas vraiment sûr que ce soit correct.
De AskTom
(dans 9i, il y a un nouveau "saut d'index" - recherchez-le pour en savoir plus. Il rend l'index (a, b) OR (b, a) utile dans les deux cas ci-dessus parfois!)
Ainsi, l'ordre des colonnes dans votre index dépend de la façon dont vos requêtes sont écrites. Vous voulez être en mesure d'utiliser l'index pour autant de requêtes que vous le pouvez (afin de réduire le nombre total d'index que vous avez) - cela déterminera l'ordre des colonnes. Rien d'autre (la sélectivité de a ou b ne compte pas du tout).
L'un des arguments pour organiser les colonnes dans l'index composite dans l'ordre des moins discriminantes (valeurs moins distinctes) aux plus discriminantes (valeurs plus distinctes) est la compression des clés d'index.
SQL> create table t as select * from all_objects;
Table created.
SQL> create index t_idx_1 on t(owner,object_type,object_name);
Index created.
SQL> create index t_idx_2 on t(object_name,object_type,owner);
Index created.
SQL> select count(distinct owner), count(distinct object_type), count(distinct object_name ), count(*) from t;
COUNT(DISTINCTOWNER) COUNT(DISTINCTOBJECT_TYPE) COUNT(DISTINCTOBJECT_NAME) COUNT(*)
-------------------- -------------------------- -------------------------- ----------
30 45 52205 89807
SQL> analyze index t_idx_1 validate structure;
Index analyzed.
SQL> select btree_space, pct_used, opt_cmpr_count, opt_cmpr_pctsave from index_stats;
BTREE_SPACE PCT_USED OPT_CMPR_COUNT OPT_CMPR_PCTSAVE
----------- ---------- -------------- ----------------
5085584 90 2 28
SQL> analyze index t_idx_2 validate structure;
Index analyzed.
SQL> select btree_space, pct_used, opt_cmpr_count, opt_cmpr_pctsave from index_stats;
BTREE_SPACE PCT_USED OPT_CMPR_COUNT OPT_CMPR_PCTSAVE
----------- ---------- -------------- ----------------
5085584 90 1 14
Selon les statistiques de l'indice, le premier indice est plus compressible.
Un autre est la façon dont l'index est utilisé dans vos requêtes. Si vos requêtes utilisent principalement col1
,
Par exemple, si vous avez des requêtes comme-
select * from t where col1 = :a and col2 = :b;
select * from t where col1 = :a;
-alors index(col1,col2)
fonctionnerait mieux.
Si vos requêtes utilisent principalement col2
,
select * from t where col1 = :a and col2 = :b;
select * from t where col2 = :b;
-alors index(col2,col1)
fonctionnerait mieux. Si toutes vos requêtes spécifient toujours les deux colonnes, peu importe la colonne qui arrive en premier dans l'index composite.
En conclusion, les considérations clés dans l'ordre des colonnes de l'index composite sont la compression des clés d'index et la façon dont vous allez utiliser cet index dans vos requêtes.
Références:
La plus sélective en premier n'est utile que lorsque cette colonne se trouve dans la clause WHERE réelle.
Lorsque le SELECT est par un groupe plus grand (moins sélectif), puis éventuellement par d'autres valeurs non indexées, un index avec des colonnes moins sélectives peut toujours être utile (s'il y a une raison de ne pas en créer un autre).
S'il y a une ADRESSE de table, avec
COUNTRY CITY STREET, autre chose ...
l'indexation de STREET, CITY, COUNTRY produira les requêtes les plus rapides avec un nom de rue. Mais en interrogeant toutes les rues d'une ville, l'index sera inutile et la requête effectuera probablement une analyse complète de la table.
L'indexation COUNTRY, CITY, STREET peut être un peu plus lente pour les rues individuelles, mais l'index peut être utilisé pour d'autres requêtes, en sélectionnant uniquement par pays et/ou ville.
Lors du choix de l'ordre des colonnes d'index, la préoccupation principale est:
Y a-t-il des prédicats (égalité) contre cette colonne dans mes requêtes?
Si une colonne n'apparaît jamais dans une clause where, cela ne vaut pas l'indexation (1)
OK, vous avez donc un tableau et des requêtes pour chaque colonne. Parfois plus d'un.
Comment décidez-vous quoi indexer?
Regardons un exemple. Voici un tableau à trois colonnes. L'une contient 10 valeurs, 1000 autres, les 10 000 dernières:
create table t(
few_vals varchar2(10),
many_vals varchar2(10),
lots_vals varchar2(10)
);
insert into t
with rws as (
select lpad(mod(rownum, 10), 10, '0'),
lpad(mod(rownum, 1000), 10, '0'),
lpad(rownum, 10, '0')
from dual connect by level <= 10000
)
select * from rws;
commit;
select count(distinct few_vals),
count(distinct many_vals) ,
count(distinct lots_vals)
from t;
COUNT(DISTINCTFEW_VALS) COUNT(DISTINCTMANY_VALS) COUNT(DISTINCTLOTS_VALS)
10 1,000 10,000
Ce sont des chiffres remplis de zéros. Cela aidera à faire le point sur la compression plus tard.
Vous avez donc trois requêtes courantes:
select count (distinct few_vals || ':' || many_vals || ':' || lots_vals )
from t
where few_vals = '0000000001';
select count (distinct few_vals || ':' || many_vals || ':' || lots_vals )
from t
where lots_vals = '0000000001';
select count (distinct few_vals || ':' || many_vals || ':' || lots_vals )
from t
where lots_vals = '0000000001'
and few_vals = '0000000001';
Qu'indexez-vous?
Un index sur seulement few_vals n'est que légèrement meilleur qu'un scan de table complet:
select count (distinct few_vals || ':' || many_vals || ':' || lots_vals )
from t
where few_vals = '0000000001';
select *
from table(dbms_xplan.display_cursor(null, null, 'IOSTATS LAST -PREDICATE'));
-------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
-------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 1 |00:00:00.01 | 61 |
| 1 | SORT AGGREGATE | | 1 | 1 | 1 |00:00:00.01 | 61 |
| 2 | VIEW | VW_DAG_0 | 1 | 1000 | 1000 |00:00:00.01 | 61 |
| 3 | HASH GROUP BY | | 1 | 1000 | 1000 |00:00:00.01 | 61 |
| 4 | TABLE ACCESS FULL| T | 1 | 1000 | 1000 |00:00:00.01 | 61 |
-------------------------------------------------------------------------------------------
select /*+ index (t (few_vals)) */
count (distinct few_vals || ':' || many_vals || ':' || lots_vals )
from t
where few_vals = '0000000001';
select *
from table(dbms_xplan.display_cursor(null, null, 'IOSTATS LAST -PREDICATE'));
-------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
-------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 1 |00:00:00.01 | 58 |
| 1 | SORT AGGREGATE | | 1 | 1 | 1 |00:00:00.01 | 58 |
| 2 | VIEW | VW_DAG_0 | 1 | 1000 | 1000 |00:00:00.01 | 58 |
| 3 | HASH GROUP BY | | 1 | 1000 | 1000 |00:00:00.01 | 58 |
| 4 | TABLE ACCESS BY INDEX ROWID BATCHED| T | 1 | 1000 | 1000 |00:00:00.01 | 58 |
| 5 | INDEX RANGE SCAN | FEW | 1 | 1000 | 1000 |00:00:00.01 | 5 |
-------------------------------------------------------------------------------------------------------------
Il ne vaut donc probablement pas la peine d'être indexé seul. Les requêtes sur lots_vals renvoient quelques lignes (seulement 1 dans ce cas). Donc, cela vaut vraiment la peine d'être indexé.
Mais qu'en est-il des requêtes sur les deux colonnes?
Devriez-vous indexer:
( few_vals, lots_vals )
OR
( lots_vals, few_vals )
Question piège!
La réponse n'est ni l'un ni l'autre.
Bien sûr, few_vals est une longue chaîne. Vous pouvez donc en tirer une bonne compression. Et vous (pourriez) obtenir une analyse de saut d'index pour les requêtes en utilisant (few_vals, lots_vals) qui n'ont que des prédicats sur lots_vals. Mais je ne le fais pas ici, même s'il fonctionne nettement mieux qu'une analyse complète:
create index few_lots on t(few_vals, lots_vals);
select count (distinct few_vals || ':' || many_vals || ':' || lots_vals )
from t
where lots_vals = '0000000001';
select *
from table(dbms_xplan.display_cursor(null, null, 'IOSTATS LAST -PREDICATE'));
-------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
-------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 1 |00:00:00.01 | 61 |
| 1 | SORT AGGREGATE | | 1 | 1 | 1 |00:00:00.01 | 61 |
| 2 | VIEW | VW_DAG_0 | 1 | 1 | 1 |00:00:00.01 | 61 |
| 3 | HASH GROUP BY | | 1 | 1 | 1 |00:00:00.01 | 61 |
| 4 | TABLE ACCESS FULL| T | 1 | 1 | 1 |00:00:00.01 | 61 |
-------------------------------------------------------------------------------------------
select /*+ index_ss (t few_lots) */count (distinct few_vals || ':' || many_vals || ':' || lots_vals )
from t
where lots_vals = '0000000001';
select *
from table(dbms_xplan.display_cursor(null, null, 'IOSTATS LAST -PREDICATE'));
----------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads |
----------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 1 |00:00:00.01 | 13 | 11 |
| 1 | SORT AGGREGATE | | 1 | 1 | 1 |00:00:00.01 | 13 | 11 |
| 2 | VIEW | VW_DAG_0 | 1 | 1 | 1 |00:00:00.01 | 13 | 11 |
| 3 | HASH GROUP BY | | 1 | 1 | 1 |00:00:00.01 | 13 | 11 |
| 4 | TABLE ACCESS BY INDEX ROWID BATCHED| T | 1 | 1 | 1 |00:00:00.01 | 13 | 11 |
| 5 | INDEX SKIP SCAN | FEW_LOTS | 1 | 40 | 1 |00:00:00.01 | 12 | 11 |
----------------------------------------------------------------------------------------------------------------------
Aimez-vous le jeu? (2)
Vous avez donc toujours besoin d'un index avec lots_vals comme colonne de tête. Et au moins dans ce cas, l'indice composé (peu, beaucoup) fait la même quantité de travail qu'un seul sur (lots)
select count (distinct few_vals || ':' || many_vals || ':' || lots_vals )
from t
where lots_vals = '0000000001'
and few_vals = '0000000001';
select *
from table(dbms_xplan.display_cursor(null, null, 'IOSTATS LAST -PREDICATE'));
-------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
-------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 1 |00:00:00.01 | 3 |
| 1 | SORT AGGREGATE | | 1 | 1 | 1 |00:00:00.01 | 3 |
| 2 | VIEW | VW_DAG_0 | 1 | 1 | 1 |00:00:00.01 | 3 |
| 3 | HASH GROUP BY | | 1 | 1 | 1 |00:00:00.01 | 3 |
| 4 | TABLE ACCESS BY INDEX ROWID BATCHED| T | 1 | 1 | 1 |00:00:00.01 | 3 |
| 5 | INDEX RANGE SCAN | FEW_LOTS | 1 | 1 | 1 |00:00:00.01 | 2 |
-------------------------------------------------------------------------------------------------------------
create index lots on t(lots_vals);
select /*+ index (t (lots_vals)) */count (distinct few_vals || ':' || many_vals || ':' || lots_vals )
from t
where lots_vals = '0000000001'
and few_vals = '0000000001';
select *
from table(dbms_xplan.display_cursor(null, null, 'IOSTATS LAST -PREDICATE'));
----------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads |
----------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 1 |00:00:00.01 | 3 | 1 |
| 1 | SORT AGGREGATE | | 1 | 1 | 1 |00:00:00.01 | 3 | 1 |
| 2 | VIEW | VW_DAG_0 | 1 | 1 | 1 |00:00:00.01 | 3 | 1 |
| 3 | HASH GROUP BY | | 1 | 1 | 1 |00:00:00.01 | 3 | 1 |
| 4 | TABLE ACCESS BY INDEX ROWID BATCHED| T | 1 | 1 | 1 |00:00:00.01 | 3 | 1 |
| 5 | INDEX RANGE SCAN | LOTS | 1 | 1 | 1 |00:00:00.01 | 2 | 1 |
----------------------------------------------------------------------------------------------------------------------
Il y aura des cas où l'indice composé vous fera économiser 1 à 2 E/S. Mais vaut-il la peine d'avoir deux index pour cette économie?
Et il y a un autre problème avec l'index composite. Comparez le facteur de regroupement pour les trois index, y compris LOTS_VALS:
create index lots on t(lots_vals);
create index lots_few on t(lots_vals, few_vals);
create index few_lots on t(few_vals, lots_vals);
select index_name, leaf_blocks, distinct_keys, clustering_factor
from user_indexes
where table_name = 'T';
INDEX_NAME LEAF_BLOCKS DISTINCT_KEYS CLUSTERING_FACTOR
FEW_LOTS 47 10,000 530
LOTS_FEW 47 10,000 53
LOTS 31 10,000 53
FEW 31 10 530
Notez que le facteur de clustering pour few_lots est 10x plus élevé que pour lots et lots_few! Et ceci est dans une table de démonstration avec un clustering parfait pour commencer. Dans les bases de données du monde réel, l'effet est probablement pire.
Alors qu'est-ce qui est si mauvais à ce sujet?
Le facteur de regroupement est l'un des principaux facteurs déterminant le caractère "attrayant" d'un indice. Plus il est élevé, moins l'optimiseur est susceptible de le choisir. Surtout si les lots_vals ne sont pas réellement uniques, mais ont normalement quelques lignes par valeur. Si vous n'avez pas de chance, cela pourrait suffire à faire croire à l'optimiseur qu'une analyse complète est moins chère ...
OK, donc les index composites avec few_vals et lots_vals n'ont que des avantages de cas Edge.
Qu'en est-il des requêtes filtrant plusieurs-valeurs et plusieurs-valeurs?
Les index à colonnes uniques n'offrent que de petits avantages. Mais combinés, ils renvoient peu de valeurs. Un indice composite est donc une bonne idée. Mais dans quel sens?
Si vous en placez quelques-uns en premier, la compression de la colonne de tête la réduira
create index few_many on t(many_vals, few_vals);
create index many_few on t(few_vals, many_vals);
select index_name, leaf_blocks, distinct_keys, clustering_factor
from user_indexes
where index_name in ('FEW_MANY', 'MANY_FEW');
INDEX_NAME LEAF_BLOCKS DISTINCT_KEYS CLUSTERING_FACTOR
FEW_MANY 47 1,000 10,000
MANY_FEW 47 1,000 10,000
alter index few_many rebuild compress 1;
alter index many_few rebuild compress 1;
select index_name, leaf_blocks, distinct_keys, clustering_factor
from user_indexes
where index_name in ('FEW_MANY', 'MANY_FEW');
INDEX_NAME LEAF_BLOCKS DISTINCT_KEYS CLUSTERING_FACTOR
MANY_FEW 31 1,000 10,000
FEW_MANY 34 1,000 10,000
Avec moins de valeurs différentes dans la première colonne, la compression est meilleure. Il y a donc un peu moins de travail pour lire cet index. Mais seulement légèrement. Et les deux sont déjà un bon morceau plus petit que l'original (diminution de 25% de la taille).
Et vous pouvez aller plus loin et compresser tout l'index!
alter index few_many rebuild compress 2;
alter index many_few rebuild compress 2;
select index_name, leaf_blocks, distinct_keys, clustering_factor
from user_indexes
where index_name in ('FEW_MANY', 'MANY_FEW');
INDEX_NAME LEAF_BLOCKS DISTINCT_KEYS CLUSTERING_FACTOR
FEW_MANY 20 1,000 10,000
MANY_FEW 20 1,000 10,000
Maintenant, les deux index sont de retour à la même taille. Notez que cela profite du fait qu'il existe une relation entre peu et beaucoup. Encore une fois, il est peu probable que vous constatiez ce genre d'avantages dans le monde réel.
Jusqu'à présent, nous n'avons parlé que des contrôles d'égalité. Souvent, avec des index composites, vous aurez une inégalité par rapport à l'une des colonnes. par exemple. des requêtes telles que "obtenir les commandes/expéditions/factures pour un client au cours des N derniers jours".
Si vous avez ces types de requêtes, vous voulez l'égalité par rapport à la première colonne de l'index:
select count (distinct few_vals || ':' || many_vals || ':' || lots_vals )
from t
where few_vals < '0000000002'
and many_vals = '0000000001';
select *
from table(dbms_xplan.display_cursor(null, null, 'IOSTATS LAST -PREDICATE'));
-------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
-------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 1 |00:00:00.01 | 12 |
| 1 | SORT AGGREGATE | | 1 | 1 | 1 |00:00:00.01 | 12 |
| 2 | VIEW | VW_DAG_0 | 1 | 10 | 10 |00:00:00.01 | 12 |
| 3 | HASH GROUP BY | | 1 | 10 | 10 |00:00:00.01 | 12 |
| 4 | TABLE ACCESS BY INDEX ROWID BATCHED| T | 1 | 10 | 10 |00:00:00.01 | 12 |
| 5 | INDEX RANGE SCAN | FEW_MANY | 1 | 10 | 10 |00:00:00.01 | 2 |
-------------------------------------------------------------------------------------------------------------
select count (distinct few_vals || ':' || many_vals || ':' || lots_vals )
from t
where few_vals = '0000000001'
and many_vals < '0000000002';
select *
from table(dbms_xplan.display_cursor(null, null, 'IOSTATS LAST -PREDICATE'));
----------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads |
----------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 1 |00:00:00.01 | 12 | 1 |
| 1 | SORT AGGREGATE | | 1 | 1 | 1 |00:00:00.01 | 12 | 1 |
| 2 | VIEW | VW_DAG_0 | 1 | 2 | 10 |00:00:00.01 | 12 | 1 |
| 3 | HASH GROUP BY | | 1 | 2 | 10 |00:00:00.01 | 12 | 1 |
| 4 | TABLE ACCESS BY INDEX ROWID BATCHED| T | 1 | 2 | 10 |00:00:00.01 | 12 | 1 |
| 5 | INDEX RANGE SCAN | MANY_FEW | 1 | 1 | 10 |00:00:00.01 | 2 | 1 |
----------------------------------------------------------------------------------------------------------------------
Notez qu'ils utilisent l'index opposé.
TL; DR
1: Dans certains cas, il peut être utile d'inclure une colonne dans un index si cela signifie que toutes les colonnes de votre requête se trouvent dans l'index. Cela permet une analyse d'index uniquement, vous n'avez donc pas besoin d'accéder à la table.
2: Si vous avez une licence pour les diagnostics et l'optimisation, vous pouvez forcer le plan à un saut d'analyse avec SQL Plan Management
[~ # ~] addednda [~ # ~]
PS - les documents que vous avez cités proviennent de 9i. C'est vraiment vieux. Je resterais avec quelque chose plus récent
Il y a plus d'éléments de requête qui contribuent à la décision finale sur ce qu'un index composite devrait commencer et/ou contenir en plus de la sélectivité de la colonne.
par exemple:
pour garder la conversation pertinente, ma réponse ci-dessous s'applique à la situation suivante:
D'après mon expérience, c'est à la fois que DBA devrait être attentif.
Imaginons que la seule règle soit appliquée:
1) Si je crée un index avec la colonne la plus sélective en premier mais que cette colonne n'est pas réellement utilisée par la plupart des requêtes sur cette table, cela ne sert à rien pour le moteur db.
2) Si je crée un index avec la colonne la plus utilisée dans une requête en premier dans l'index mais que la colonne a une faible sélectivité, les performances de ma requête ne seront pas bonnes.
Je vais lister les colonnes qui sont principalement utilisées dans 90% des requêtes de table. Ensuite, mettez ceux-ci uniquement dans l'ordre de la plus grande cardinalité à la moindre cardinalité.
Nous utilisons des index pour améliorer les performances des requêtes de lecture et ce flux de travail (types de requêtes de lecture) doit uniquement conduire la création d'index. En fait, au fur et à mesure que les données augmentent (des milliards de lignes), l'index compressé peut économiser du stockage, mais nuit à la performance des requêtes de lecture.
En théorie, la colonne la plus sélective donne la recherche la plus rapide. Mais au travail, je suis juste tombé sur une situation où nous avons un indice composite de 3 parties avec la partie la plus sélective en premier. (date, auteur, maison d'édition, disons, dans cet ordre, le tableau surveille les pouces vers le haut sur les messages) et j'ai une requête qui utilise les 3 parties. Mysql utilise par défaut l'index de l'auteur uniquement pour ignorer l'index composite contenant la société et la date bien qu'ils soient présents dans ma requête. J'ai utilisé force index pour utiliser le composite et la requête s'est en fait déroulée plus lentement. Pourquoi est-ce arrivé? Je vais vous dire:
Je sélectionnais une plage à la date, donc malgré une date très sélective, le fait que nous l'utilisions pour des analyses de plage (même si la plage est relativement courte, 6 mois sur 6 ans de données) a rendu le composite nocif pour mysql. Pour utiliser le composite dans ce cas particulier, mysql doit récupérer tous les articles écrits depuis les nouvelles années, puis plonger dans qui est l'auteur, et étant donné que l'auteur n'a pas écrit autant d'articles par rapport à d'autres auteurs, mysql a préféré simplement trouver cet auteur .
Dans un autre cas, la requête a été exécutée beaucoup plus rapidement sur le composite, dans le cas où un auteur était extrêmement populaire et possédait la plupart des enregistrements, le tri par date étant logique. Mais mysql n'a pas détecté automatiquement ce cas, j'ai dû forcer l'index ... Donc vous savez, ça varie. Les analyses de plage peuvent rendre votre colonne sélective inutile. La distribution des données pourrait rendre les cas où les colonnes sont plus sélectives pour différents enregistrements ...
Ce que je ferais différemment, c'est de déplacer la date (qui, en théorie, est la plus sélective) vers la droite, car je sais que je vais effectuer un balayage de plage maintenant et cela fait une différence.