J'ai deux tables, l'une d'elles contient une histoire d'URL téléchargées, tandis que l'autre table contient des détails sur chaque URL.
La requête suivante regroupe les URL par le nombre de répétitions au cours de la dernière heure.
SELECT COUNT(history.url) as total, history.url
FROM history
WHERE history.time > UNIX_TIMESTAMP()-3600
GROUP BY history.url
ORDER BY COUNT(history.url) DESC
LIMIT 30
La requête ci-dessus prend environ 800 ms à exécuter, pas assez vite, mais acceptable,
cependant, lorsqu'il y jointe avec la table de cache, la nouvelle requête prend environ 25 ans à exécuter, ce qui est très lent.
SELECT th.total, th.url, tc.url, tc.json
FROM (SELECT COUNT(history.url) as total, history.url
FROM history
WHERE history.time > UNIX_TIMESTAMP()-3600
GROUP BY history.url
ORDER BY COUNT(history.url) DESC
LIMIT 30
) th
INNER JOIN (SELECT cache.url, cache.json FROM cache) tc
ON th.url = tc.url
GROUP BY th.url
ORDER BY th.total DESC
LIMIT 30
Je pense que cela pourrait se produire car dans "TC", la table en cache entière est chargée et contient 1 Million + entrées.
Lorsque j'utilise la première requête, puis d'itérer par programme les résultats, puis exécutez une requête SELECT dans le cache pour chaque résultat, il est beaucoup plus rapide. Y a-t-il de toute façon pour accélérer ma deuxième requête?
P.s. J'utilise innodb
Mettre à jour la sortie de la deuxième requête avec expliquer
Il est généralement judicieux d'indexer des colonnes qui participent à des prédicats de jointure ou des clauses. Une erreur commune consiste à créer plusieurs index de colonne au lieu de moins d'index multi-colonnes. Ici, nous pouvons bénéficier de l'URL et du temps de l'histoire (examinez toutes les requêtes sur ces tables et vous pouvez constater que vous pouvez ajouter des colonnes supplémentaires à ces index):
CREATE INDEX x01_history_url ON HISTORY (URL, TIME);
CREATE INDEX x01_cache_url ON CACHE (URL);
Deuxièmement, essayez d'inhérent les requêtes. MySQL a des limitations sur le type de requennie de requêtes qu'il est capable de le faire, de sorte que la nidification peut provoquer des frais généraux inutiles.
SELECT COUNT(th.url) as total, tc.url, tc.json
FROM history th
JOIN cache tc
ON th.url = tc.url
WHERE th.time > UNIX_TIMESTAMP()-3600
GROUP BY tc.url, tc.json
ORDER BY COUNT(th.url) DESC
LIMIT 30
Notez que cette requête est sémantiquement différente de votre requête afin d'obtenir un résultat différent. Si tel est un problème, vous voudrez peut-être garder la limite de 30 construction dans une sous-requête comme avant. Vous pouvez également envisager si vous pouvez ajouter une limite similaire au cache, existe-t-il une limite supérieure sur le nombre de rangées de cache que vous devez enquêter pour obtenir 30 rangées au total?
INNER JOIN (SELECT cache.url, cache.json
FROM cache
ORDER BY ? LIMIT ?) tc
Pour la première requête:
SELECT COUNT(*) as total, -- * is the common pattern
url
FROM history
WHERE time > NOW() - INTERVAL 1 HOUR
GROUP BY url
ORDER BY COUNT(*) DESC
LIMIT 30
INDEX(time, url) -- in this order
INDEX(url, time) -- maybe this order
Utiliser les deux index; Différentes versions MySQL et une plage de temps différente peuvent utiliser un index par rapport à l'autre.
Pour la deuxième requête, n'utilisez pas inutilement une table dérivée:
INNER JOIN (SELECT cache.url, cache.json FROM cache) tc
ON th.url = tc.url
->
INNER JOIN cache tc
ON th.url = tc.url
Et cache
nécessite INDEX(url)
.
Les deux tables 1: 1 ou 1: plusieurs ou plusieurs: 1 ou plusieurs: beaucoup? Cela peut faire la différence pour le GROUP/ORDER/LIMIT
.
Pendant que vous y êtes, veuillez fournir SHOW CREATE TABLE
Pour les tables.