Mysql
 sql >> Database >  >> RDS >> Mysql

Implicazioni sulle prestazioni dell'utilizzo dell'alias nella clausola HAVING

Incentrato solo su quella particolare query e con dati di esempio caricati di seguito. Questo risolve alcune altre query come count(distinct ...) menzionato da altri.

L'alias in the HAVING sembra sovraperformare leggermente o piuttosto sovraperformare la sua alternativa (a seconda della query).

Questo utilizza una tabella preesistente con circa 5 milioni di righe creata rapidamente tramite questa answer dei miei che impiegano dai 3 ai 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 invece INNODB. Crea l'anomalia del gap INNODB prevista a causa degli inserimenti di prenotazione dell'intervallo. Sto solo dicendo, ma non fa differenza. 4,7 milioni di righe.

Modifica la tabella per avvicinarti allo schema ipotizzato 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à del 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, noi lo facciamo avere una clausola LIMIT.

Quindi lo stiamo facendo in mezzo milione di iterazioni di riga. Imposta una colonna su un numero casuale compreso 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 eseguire quanto sopra fino a quando non camId è nullo.

L'ho eseguito tipo 10 volte (l'intera operazione richiede dai 7 ai 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

Crea un utile indice (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

Crea 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

Esegui 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. Eseguito ciascuno una dozzina di volte.

Il EXPLAIN l'output è lo stesso 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(), ottengo un aumento delle prestazioni di circa il 12% con l'alias in having (con EXPLAIN identico output) dalle due query seguenti.

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 nell'avere è costantemente 35% più veloce con lo stesso EXPLAIN produzione. Visto sotto. Quindi è stato dimostrato due volte che lo stesso output di Spiega non si traduce nella stessa performance, ma come 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'ottimizzatore sembra favorire l'alias in questo momento, specialmente per il DISTINCT.