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

Ydeevneimplikationer af at tillade, at alias bruges i HAVING-klausulen

Snævert fokuseret på netop den specifikke forespørgsel og med eksempeldata indlæst nedenfor. Dette adresserer nogle andre forespørgsler såsom count(distinct ...) nævnt af andre.

alias in the HAVING ser ud til enten at klare sig lidt eller en del bedre end sit alternativ (afhængigt af forespørgslen).

Dette bruger en allerede eksisterende tabel med omkring 5 millioner rækker i den oprettet hurtigt via dette svar af mine, hvilket tager 3 til 5 minutter.

Resulterende struktur:

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;
 

Men bruger INNODB i stedet. Opretter den forventede INNODB-gab-anomali på grund af områdereservationsindsætningerne. Siger det bare, men gør ingen forskel. 4,7 millioner rækker.

Rediger tabellen for at komme tæt på Tims antagne skema.

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
 

Det følgende vil tage et stykke tid. Kør det igen og igen i bidder, ellers kan din forbindelse blive timeout. Timeoutet skyldes 5 millioner rækker uden en LIMIT-klausul i opdateringserklæringen. Bemærk, det gør vi har en LIMIT-klausul.

Så vi gør det i en halv million række iterationer. Indstiller en kolonne til et tilfældigt tal mellem 1 og 20

update students set camId=floor(rand()*20+1) where camId is null limit 500000; -- well that took a while (no surprise)
 

Fortsæt med at køre ovenstående, indtil der ikke er nogen camId er nul.

Jeg kørte det 10 gange (det hele tager 7 til 10 minutter)

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
 

Opret et nyttigt indeks (naturligvis efter indsættelserne).

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
 

Opret campustabellen.

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
 

Kør de to forespørgsler:

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
 

og

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
 

Så tiderne er identiske. Løb hver et dusin gange.

EXPLAIN output er det samme for begge

+----+-------------+----------+------+---------------+------------+---------+----------------------+--------+---------------------------------+ | 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 | +----+-------------+----------+------+---------------+------------+---------+----------------------+--------+---------------------------------+

Ved at bruge AVG()-funktionen får jeg omkring 12 % stigning i ydeevnen med aliaset i having (med identiske EXPLAIN output) fra følgende to forespørgsler.

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
 

Og til sidst, 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
 

Aliaset i have kører konsekvent 35 % hurtigere med den samme EXPLAIN produktion. Ses nedenfor. Så det samme Explain-output har vist sig to gange ikke at resultere i den samme præstation, men som et generelt fingerpeg.

+----+-------------+----------+-------+---------------+------------+---------+----------------------+--------+----------------------------------------------+ | 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 | +----+-------------+----------+-------+---------------+------------+---------+----------------------+--------+----------------------------------------------+

Optimeringsværktøjet ser ud til at favorisere aliaset i have i øjeblikket, især for DISTINCT.



  1. Er der nogen god universel PHP MySQL HTTP-tunnel?

  2. Er det muligt at indsætte en ny række øverst i MySQL-tabellen?

  3. Awesome 24 Concurrent Manager Interview spørgsmål

  4. Henter data fra MySQL-database til html-rulleliste