Beperkt gericht op alleen die specifieke zoekopdracht, en met voorbeeldgegevens die hieronder zijn geladen. Dit behandelt enkele andere vragen, zoals de count(distinct ...)
door anderen genoemd.
De alias in the HAVING
lijkt ofwel iets beter te presteren dan zijn alternatief (afhankelijk van de zoekopdracht).
Dit maakt gebruik van een reeds bestaande tabel met ongeveer 5 miljoen rijen erin, snel gemaakt via dit antwoord van mij die 3 tot 5 minuten duurt.
Resulterende structuur:
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;
Maar in plaats daarvan INNODB gebruiken. Creëert de verwachte INNODB-gapafwijking vanwege de invoegingen van de bereikreservering. Zeg het maar, maar maakt niet uit. 4,7 miljoen rijen.
Pas de tabel aan om in de buurt van Tims veronderstelde schema te komen.
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
Het volgende duurt even. Voer het opnieuw en opnieuw in stukjes uit, anders kan uw verbinding een time-out krijgen. De time-out is te wijten aan 5 miljoen rijen zonder een LIMIT-clausule in de update-instructie. Let op, we doen een LIMIT-clausule hebben.
Dus we doen het in een half miljoen rij-iteraties. Stelt een kolom in op een willekeurig getal tussen 1 en 20
update students set camId=floor(rand()*20+1) where camId is null limit 500000; -- well that took a while (no surprise)
Blijf het bovenstaande uitvoeren totdat er geen camId
. is is nul.
Ik heb het 10 keer gedaan (het hele ding duurt 7 tot 10 minuten)
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
Maak een handige index (uiteraard na de invoegingen).
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
Maak de campustafel.
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
Voer de twee zoekopdrachten uit:
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
en
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
De tijden zijn dus identiek. Elk een dozijn keer gerend.
De EXPLAIN
output is hetzelfde voor beide
+----+-------------+----------+------+---------------+------------+---------+----------------------+--------+---------------------------------+
| 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 |
+----+-------------+----------+------+---------------+------------+---------+----------------------+--------+---------------------------------+
Als ik de functie AVG() gebruik, krijg ik een prestatieverbetering van ongeveer 12% met de alias in de having
(met identieke EXPLAIN
output) van de volgende twee zoekopdrachten.
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
En als laatste, de 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
De alias in het hebben werkt consequent 35% sneller met dezelfde EXPLAIN
uitvoer. Hieronder te zien. Dus dezelfde Explain-output is twee keer getoond om niet tot dezelfde prestatie te leiden, maar als een algemene aanwijzing.
+----+-------------+----------+-------+---------------+------------+---------+----------------------+--------+----------------------------------------------+
| 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 |
+----+-------------+----------+-------+---------------+------------+---------+----------------------+--------+----------------------------------------------+
De Optimizer lijkt op dit moment de voorkeur te geven aan de alias in het hebben, vooral voor de DISTINCT.