Strettamente focalizzato solo su quella particolare query e con i dati di esempio caricati di seguito. Questo risolve alcune altre domande come la count(distinct ...)
menzionata da altri.
Il alias in the HAVING
sembra leggermente sovraperformare o leggermente superiore alla sua alternativa (a seconda della query).
Questo utilizza una tabella preesistente con circa 5 milioni di righe in esso create rapidamente tramite questo answer del mio che richiede da 3 a 5 minuti.
struttura risultante:
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;
Ma usando INNODB invece. Crea l'anomalia di gap INNODB prevista a causa degli inserimenti di prenotazione range. Sto solo dicendo, ma non fa differenza. 4,7 milioni di righe.
Modificare la tabella per avvicinarsi allo schema assunto da 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
Quanto segue richiederà un po 'di tempo. Eseguilo ancora e ancora in blocchi, altrimenti la tua connessione potrebbe scadere. Il timeout è dovuto a 5 milioni di righe senza una clausola LIMIT nell'istruzione di aggiornamento. Nota, abbiamo do avere una clausola LIMIT.
Quindi lo stiamo facendo in mezzo milione di iterazioni di righe. Imposta una colonna a un numero casuale tra 1 e 20
update students set camId=floor(rand()*20+1) where camId is null limit 500000; -- well that took a while (no surprise)
Continua a correre il precedente finché non camId
è nullo.
ho fatto funzionare come 10 volte (il tutto prende 7 a 10 minuti)
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
Creare un indice utile (dopo gli inserti ovviamente).
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
Creare la tabella del 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
Eseguire le due query:
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
e
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
Quindi i tempi sono identici. Esegui ciascuna una dozzina di volte.
Il EXPLAIN
uscita è la stessa per entrambi
+----+-------------+----------+------+---------------+------------+---------+----------------------+--------+---------------------------------+
| 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 |
+----+-------------+----------+------+---------------+------------+---------+----------------------+--------+---------------------------------+
Utilizzando la funzione AVG(), sto ottenendo circa un aumento del 12% in termini di prestazioni con l'alias nella having
(con identico EXPLAIN
uscita) dal seguendo due domande.
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
E, infine, il 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 nel dover corre costantemente più veloceil 35% con la stessa EXPLAIN
uscita. Visto di seguito Quindi lo stesso output di Explain è stato mostrato due volte per non dare la stessa performance, ma come un indizio generale.
+----+-------------+----------+-------+---------------+------------+---------+----------------------+--------+----------------------------------------------+
| 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'Optimizer sembra favorire l'alias nel avendo in questo momento, soprattutto per il DISTINCT.
Faccio un pazzo fuori di me tutto il tempo. – Drew
Possibile duplicato di [Parametrizzare una clausola SQL IN] (http://stackoverflow.com/questions/337704/parameterize-an-sql-in-clause) –