sql >> Databasteknik >  >> RDS >> Mysql

Prestandakonsekvenser av att tillåta att alias används i HAVING-klausulen

Snävt fokuserad på just den specifika frågan, och med exempeldata laddade nedan. Detta adresserar vissa andra frågor såsom count(distinct ...) nämnt av andra.

alias in the HAVING verkar antingen överträffa något eller ganska mycket bättre än sitt alternativ (beroende på frågan).

Detta använder en redan existerande tabell med cirka 5 miljoner rader som skapas snabbt via detta svar av mig som tar 3 till 5 minuter.

Resulterande 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 använder INNODB istället. Skapar den förväntade INNODB-gapavvikelsen på grund av intervallreservationsinsättningarna. Säger bara, men gör ingen skillnad. 4,7 miljoner rader.

Ändra tabellen för att komma nära Tims antagna schema.

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

Följande kommer att ta ett tag. Kör det igen och igen i bitar, annars kan din anslutning timeout. Timeouten beror på 5 miljoner rader utan en LIMIT-klausul i uppdateringsförklaringen. Observera att vi gör har en LIMIT-klausul.

Så vi gör det i en halv miljon radupprepningar. Ställer in en kolumn till ett slumptal mellan 1 och 20

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

Fortsätt köra ovanstående tills inget camId är null.

Jag körde det typ 10 gånger (det hela tar 7 till 10 minuter)

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

Skapa ett användbart register (naturligtvis efter inläggen).

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

Skapa 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 två frågorna:

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

och

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å tiderna är identiska. Sprang var och en ett dussin gånger.

EXPLAIN utgången är densamma för båda

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

Genom att använda AVG()-funktionen får jag ungefär 12 % ökning i prestanda med aliaset i having (med identisk EXPLAIN output) från följande två frågor.

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

Och slutligen, 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 att ha löper konsekvent 35 % snabbare med samma EXPLAIN produktion. Ses nedan. Så samma Explain-utdata har visats två gånger för att inte resultera i samma prestanda, utan som en allmän ledtråd.

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

Optimeraren verkar gynna aliaset i att ha för tillfället, särskilt för DISTINCT.



  1. Användarkontohantering, roller, behörigheter, autentisering PHP och MySQL - Del 4

  2. inkludera Jfactory-klassen i en extern php-fil, Joomla

  3. Uppdatera tabell med SUM från en annan tabell

  4. Hur man återställer plåstret efter misslyckad cutover-fas i R12.2