Mysql
 sql >> Base de données >  >> RDS >> Mysql

Incidences sur les performances de l'autorisation d'utiliser un alias dans la clause HAVING

É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.