J'ai lu des articles sur l' FORCE
index, mais comment puis-je forcer MySQL à IGNORE ALL
indexer?
J'ai essayé SELECT * FROM tbl IGNORE INDEX(*)
, mais je n'ai pas réussi.
Quant à savoir pourquoi j'ai (et d'autres) besoin de le faire: Par exemple, j'avais besoin de résumer les statistiques des référents par tld comme ceci:
SELECT
count(*) as c,
SUBSTRING
(
domain_name,
LENGTH(domain_name) - LOCATE('.', REVERSE(domain_name)) + 2
) as tld
FROM `domains_import`
IGNORE INDEX(domain_name)
GROUP BY tld
ORDER BY c desc
LIMIT 100
... mais je dois toujours regarder quels index sont définis ou déterminer quel index sera utilisé via Explain. Il serait très pratique d'écrire IGNORE INDEX ALL
simplement et de ne pas s'en soucier.
Est-ce que quelqu'un connaît la syntaxe ou un hack? (Des dizaines de lignes via les tables de définition MySQL ne sont vraiment pas un raccourci).
Ajouté à partir de la discussion par chat :
Bechmark:
pas d'index = 148,5 secondes
avec index = 180 secondes et toujours en cours d'exécution avec l'envoi de données La baie SSD est si puissante que vous ne vous souciez presque pas du cache de données ...
Définition de référence:
CREATE TABLE IF NOT EXISTS `domains_import` (
`domain_id` bigint(20) unsigned NOT NULL,
`domain_name` varchar(253) CHARACTER SET ascii COLLATE ascii_bin NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
ALTER TABLE `domains_import`
ADD PRIMARY KEY (`domain_id`),
ADD UNIQUE KEY `domain_name` (`domain_name`);
ALTER TABLE `domains_import`
MODIFY `domain_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT;
InnoDB, le test avec index (pas USE INDEX () ou similaire) est toujours en cours d'exécution, 250 secondes, je viens de le tuer.
LEFT JOIN
que j'avais. `USE INDEX ()` a obligé MySQL à faire un scan de table sur une table de 20K lignes et 1 à 1JOIN
s au lieu de croiser 500 lignes entre deux index. 20 fois plus rapide.Vous pouvez également intégrer
WHERE 1=1
ypercube vient de me demander
Oui, mais vous avez donné à MySQL une requête vraiment stupide.
1=1
reviendrait à l'indice clusterisé. Nonobstant, il existe encore un autre moyen, mais cela nécessite d'être un peu malveillant pour l'Optimizer.Cela jettera chaque index sous le bus à coup sûr, car la valeur de chaque ligne doit
domain_name
être vérifiée. Sidomain_name
est indexé, vous devez choisir une colonne pour celleWHERE column_name=column_name
qui n'est pas indexée du tout.Je viens d'essayer cela sur une grande table dans un serveur de transfert
Aucun index n'est choisi
la source
WHERE id+0 = id*1
l'index sera toujours utilisé, et un extraUsing where
apparaîtra.En supposant que vous ayez ces deux index:
Peu importe alors ce que fait l'optimiseur; il doit balayer essentiellement une quantité identique de choses.
Cas 1: il effectue une analyse de table (ou utilise domain_id): il analysera les paires (id, nom), localisera tous les noms, effectuera SUBSTRING..LOCATE, GROUP BY et enfin ORDER BY. Le GROUP BY et le ORDER BY ont probablement besoin chacun d'une table tmp et d'un tri de fichiers. Vérifiez
EXPLAIN SELECT ...
si c'est le cas.Cas 2: il effectue un balayage d'index (de nom_domaine): cet index contient en fait des paires (nom, id) - car InnoDB place implicitement le PK à la fin de toute clé secondaire. Le reste du traitement est parallèle au cas 1.
Une chose pourrait être différente - la taille des deux BTrees. Faites
SHOW TABLE STATUS LIKE domains_import
pour voir la Data_length (pour le cas 1) et Index_length (pour le cas 2). Le plus grand BTree sera plus lent.Une autre chose pourrait être différente - la mise en cache. Quelle est la valeur de
innodb_buffer_pool_size
? De combien de RAM disposez-vous? Les données (ou index) peuvent-elles être contenues dans le pool de tampons? (Ou en sera-t-il à 37%, car il s'agit d'une analyse de table / index?) Si cela convient, exécutez la requête deux fois. La deuxième fois sera environ 10 fois plus rapide car il ne frappera pas le disque (mise en cache).S'il s'agit d'une tâche unique, le SSD vous aidera. Si ce n'est pas le cas, et que vous pouvez mettre en cache la table entière, cela n'aidera pas après le chargement du buffer_pool.
la source