Étroitement concentré sur cette requête particulière, et avec des exemples de données chargés ci-dessous. Cela répond à d'autres requêtes telles que le count(distinct ...)
mentionné par d'autres.
L'alias alias in the HAVING
semble surpasser légèrement ou légèrement son alternative (selon la requête).
Cela utilise une table préexistante avec environ 5 millions de lignes créées rapidement via cette réponse du mien qui prend 3 à 5 minutes.
Structure résultante :
CREATE TABLE `ratings` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`thing` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5046214 DEFAULT CHARSET=utf8;
Mais en utilisant INNODB à la place. Crée l'anomalie d'écart INNODB attendue en raison des insertions de réservation de plage. Je dis juste, mais ça ne change rien. 4,7 millions de lignes.
Modifiez le tableau pour vous rapprocher du schéma supposé de Tim.
rename table ratings to students; -- not exactly instanteous (a COPY)
alter table students add column camId int; -- get it near Tim's schema
-- don't add the `camId` index yet
La suite prendra du temps. Exécutez-le encore et encore par morceaux, sinon votre connexion risque d'expirer. Le délai d'attente est dû à 5 millions de lignes sans clause LIMIT dans l'instruction de mise à jour. Remarque :nous faisons avoir une clause LIMIT.
Nous le faisons donc en un demi-million d'itérations de lignes. Définit une colonne sur un nombre aléatoire entre 1 et 20
update students set camId=floor(rand()*20+1) where camId is null limit 500000; -- well that took a while (no surprise)
Continuez à exécuter ce qui précède jusqu'à ce qu'il n'y ait plus de camId
est nul.
Je l'ai exécuté environ 10 fois (le tout prend 7 à 10 minutes)
select camId,count(*) from students
group by camId order by 1 ;
1 235641
2 236060
3 236249
4 235736
5 236333
6 235540
7 235870
8 236815
9 235950
10 235594
11 236504
12 236483
13 235656
14 236264
15 236050
16 236176
17 236097
18 235239
19 235556
20 234779
select count(*) from students;
-- 4.7 Million rows
Créez un index utile (après les insertions bien sûr).
create index `ix_stu_cam` on students(camId); -- takes 45 seconds
ANALYZE TABLE students; -- update the stats: http://dev.mysql.com/doc/refman/5.7/en/analyze-table.html
-- the above is fine, takes 1 second
Créez la table du campus.
create table campus
( camID int auto_increment primary key,
camName varchar(100) not null
);
insert campus(camName) values
('one'),('2'),('3'),('4'),('5'),
('6'),('7'),('8'),('9'),('ten'),
('etc'),('etc'),('etc'),('etc'),('etc'),
('etc'),('etc'),('etc'),('etc'),('twenty');
-- ok 20 of them
Exécutez les deux requêtes :
SELECT students.camID, campus.camName, COUNT(students.id) as studentCount
FROM students
JOIN campus
ON campus.camID = students.camID
GROUP BY students.camID, campus.camName
HAVING COUNT(students.id) > 3
ORDER BY studentCount;
-- run it many many times, back to back, 5.50 seconds, 20 rows of output
et
SELECT students.camID, campus.camName, COUNT(students.id) as studentCount
FROM students
JOIN campus
ON campus.camID = students.camID
GROUP BY students.camID, campus.camName
HAVING studentCount > 3
ORDER BY studentCount;
-- run it many many times, back to back, 5.50 seconds, 20 rows of output
Les horaires sont donc identiques. Couru chacun une douzaine de fois.
Le EXPLAIN
la sortie est la même pour les deux
+----+-------------+----------+------+---------------+------------+---------+----------------------+--------+---------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------+------+---------------+------------+---------+----------------------+--------+---------------------------------+
| 1 | SIMPLE | campus | ALL | PRIMARY | NULL | NULL | NULL | 20 | Using temporary; Using filesort |
| 1 | SIMPLE | students | ref | ix_stu_cam | ix_stu_cam | 5 | bigtest.campus.camID | 123766 | Using index |
+----+-------------+----------+------+---------------+------------+---------+----------------------+--------+---------------------------------+
En utilisant la fonction AVG(), j'obtiens une augmentation d'environ 12 % des performances avec l'alias dans le having
(avec EXPLAIN
identique
output) à partir des deux requêtes suivantes.
SELECT students.camID, campus.camName, avg(students.id) as studentAvg
FROM students
JOIN campus
ON campus.camID = students.camID
GROUP BY students.camID, campus.camName
HAVING avg(students.id) > 2200000
ORDER BY students.camID;
-- avg time 7.5
explain
SELECT students.camID, campus.camName, avg(students.id) as studentAvg
FROM students
JOIN campus
ON campus.camID = students.camID
GROUP BY students.camID, campus.camName
HAVING studentAvg > 2200000
ORDER BY students.camID;
-- avg time 6.5
Et enfin, le DISTINCT
:
SELECT students.camID, count(distinct students.id) as studentDistinct
FROM students
JOIN campus
ON campus.camID = students.camID
GROUP BY students.camID
HAVING count(distinct students.id) > 1000000
ORDER BY students.camID; -- 10.6 10.84 12.1 11.49 10.1 9.97 10.27 11.53 9.84 9.98
-- 9.9
SELECT students.camID, count(distinct students.id) as studentDistinct
FROM students
JOIN campus
ON campus.camID = students.camID
GROUP BY students.camID
HAVING studentDistinct > 1000000
ORDER BY students.camID; -- 6.81 6.55 6.75 6.31 7.11 6.36 6.55
-- 6.45
L'alias dans l'ayant s'exécute systématiquement 35 % plus rapidement avec le même EXPLAIN
production. Vu ci-dessous. Ainsi, la même sortie d'Explique a été montrée deux fois pour ne pas donner les mêmes performances, mais comme un indice général.
+----+-------------+----------+-------+---------------+------------+---------+----------------------+--------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------+-------+---------------+------------+---------+----------------------+--------+----------------------------------------------+
| 1 | SIMPLE | campus | index | PRIMARY | PRIMARY | 4 | NULL | 20 | Using index; Using temporary; Using filesort |
| 1 | SIMPLE | students | ref | ix_stu_cam | ix_stu_cam | 5 | bigtest.campus.camID | 123766 | Using index |
+----+-------------+----------+-------+---------------+------------+---------+----------------------+--------+----------------------------------------------+
L'optimiseur semble favoriser l'alias dans l'avoir pour le moment, en particulier pour le DISTINCT.