Mysql
 sql >> Datenbank >  >> RDS >> Mysql

Auswirkungen auf die Leistung, wenn Aliasnamen in der HAVING-Klausel verwendet werden dürfen

Eng konzentriert auf nur diese bestimmte Abfrage und mit unten geladenen Beispieldaten. Dies adressiert einige andere Abfragen wie count(distinct ...) von anderen erwähnt.

Der alias in the HAVING scheint seine Alternative entweder leicht oder ziemlich zu übertreffen (abhängig von der Abfrage).

Dies verwendet eine bereits vorhandene Tabelle mit etwa 5 Millionen Zeilen, die schnell über diese Antwort erstellt wurde von mir, was 3 bis 5 Minuten dauert.

Resultierende 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;

Aber stattdessen INNODB verwenden. Erzeugt die erwartete INNODB-Lückenanomalie aufgrund der Bereichsreservierungseinfügungen. Nur sagen, macht aber keinen Unterschied. 4,7 Millionen Zeilen.

Ändern Sie die Tabelle, um in die Nähe von Tims angenommenem Schema zu kommen.

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

Das Folgende wird eine Weile dauern. Führen Sie es immer wieder in Blöcken aus, da Ihre Verbindung sonst möglicherweise abbricht. Die Zeitüberschreitung ist auf 5 Millionen Zeilen ohne eine LIMIT-Klausel in der Update-Anweisung zurückzuführen. Beachten Sie, dass wir tun eine LIMIT-Klausel haben.

Also machen wir es in einer halben Million Zeileniterationen. Setzt eine Spalte auf eine Zufallszahl zwischen 1 und 20

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

Führen Sie das Obige weiter aus, bis keine camId mehr vorhanden ist ist null.

Ich habe es ungefähr 10 Mal ausgeführt (das Ganze dauert 7 bis 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

Erstellen Sie einen nützlichen Index (natürlich nach den Einfügungen).

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

Erstellen Sie die Campus-Tabelle.

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

Führen Sie die beiden Abfragen aus:

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

und

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

Die Zeiten sind also identisch. Lief jeweils ein Dutzend Mal.

Der EXPLAIN Die Ausgabe ist für beide gleich

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

Mit der AVG()-Funktion erhalte ich mit dem Alias ​​im having eine Leistungssteigerung von etwa 12 % (mit identischem EXPLAIN Ausgabe) aus den folgenden zwei Abfragen.

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

Und schließlich das 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

Der Alias ​​in the have läuft konstant 35 % schneller mit dem gleichen EXPLAIN Ausgang. Unten gesehen. Daher wurde dieselbe Explain-Ausgabe zweimal gezeigt, um nicht dieselbe Leistung zu erzielen, sondern als allgemeiner Hinweis.

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

Der Optimierer scheint im Moment den Alias ​​zu bevorzugen, besonders für DISTINCT.