sql >> Database >  >> RDS >> Mysql

Prestatie-implicaties van het toestaan ​​van het gebruik van een alias in de HAVING-clausule

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.



  1. Top 115 SQL-interviewvragen die u in 2022 moet voorbereiden

  2. Opatch in niet-interactieve vorm uitvoeren

  3. #1221 - Onjuist gebruik van UPDATE en ORDER BY

  4. Een inleiding tot de Java Security API