Mysql
 sql >> Baza danych >  >> RDS >> Mysql

Wpływ na wydajność zezwolenia na użycie aliasu w klauzuli HAVING

Skoncentrowany wąsko tylko na tym konkretnym zapytaniu, z przykładowymi danymi załadowanymi poniżej. To odnosi się do niektórych innych zapytań, takich jak count(distinct ...) wspomniane przez innych.

Alias ​​alias in the HAVING wydaje się być albo nieco lepszy, albo całkiem lepszy od swojej alternatywy (w zależności od zapytania).

Wykorzystuje to istniejącą wcześniej tabelę z około 5 milionami wierszy utworzoną szybko za pomocą tej odpowiedzi mojego, co zajmuje od 3 do 5 minut.

Wynikowa struktura:

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;

Ale zamiast tego używam INNODB. Tworzy oczekiwaną anomalię przerwy INNODB ze względu na wstawienie rezerwacji zakresu. Tylko mówię, ale nie ma to znaczenia. 4,7 miliona rzędów.

Zmodyfikuj tabelę, aby zbliżyć się do założonego schematu Tima.

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

To zajmie trochę czasu. Uruchamiaj go raz za razem w kawałkach, w przeciwnym razie połączenie może wygasnąć. Limit czasu wynika z 5 milionów wierszy bez klauzuli LIMIT w instrukcji aktualizacji. Uwaga, tak mieć klauzulę LIMIT.

Więc robimy to w iteracjach pół miliona wierszy. Ustawia kolumnę na liczbę losową od 1 do 20

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

Kontynuuj powyższe, aż nie będzie camId jest zerowe.

Uruchomiłem to jak 10 razy (całość trwa od 7 do 10 minut)

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

Utwórz przydatny indeks (oczywiście po wstawkach).

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

Utwórz tabelę kampusową.

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

Uruchom dwa zapytania:

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

i

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

Więc czasy są identyczne. Uruchomiono każdy kilkanaście razy.

EXPLAIN dane wyjściowe są takie same dla obu

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

Używając funkcji AVG(), uzyskuję około 12% wzrost wydajności dzięki aliasowi w having (z identycznym EXPLAIN wyjście) z następujących dwóch zapytań.

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

I wreszcie, 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

Alias ​​w posiadaniu stale działa 35% szybciej z tym samym EXPLAIN wyjście. Widziane poniżej. Tak więc te same dane wyjściowe wyjaśniania zostały pokazane dwukrotnie, aby nie dać takiej samej wydajności, ale jako ogólna wskazówka.

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

Optymalizator wydaje się faworyzować alias w posiadaniu w tej chwili, szczególnie w przypadku DISTINCT.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Mieszanie MySQL Damerau–Levenshtein Fuzzy z Like Wildcard

  2. Zapytanie MySQL oszalał?

  3. Różnica między FIELD() i FIND_IN_SET() w MySQL

  4. Emoji nie są wstawiane w węźle bazy danych js mysql

  5. Nieznana kolumna w miejscu klauzuli