Mysql
 sql >> база данни >  >> RDS >> Mysql

Последици за производителността от разрешаването на използването на псевдоним в клаузата HAVING

Тясно фокусиран само върху тази конкретна заявка и с примерни данни, заредени по-долу. Това адресира някои други заявки като count(distinct ...) споменати от други.

alias in the HAVING изглежда леко превъзхожда или доста надминава алтернативата си (в зависимост от заявката).

Това използва вече съществуваща таблица с около 5 милиона реда в нея, създадена бързо чрез този отговор моето, което отнема от 3 до 5 минути.

Получена структура:

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;

Но вместо това се използва INNODB. Създава очакваната аномалия на INNODB празнина поради вмъкванията за резервация на диапазон. Просто казвам, но няма разлика. 4,7 милиона реда.

Променете таблицата, за да се доближите до предполагаемата схема на Тим.

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

Следното ще отнеме известно време. Стартирайте го отново и отново на парчета, в противен случай връзката ви може да изтече. Времето за изчакване се дължи на 5 милиона реда без клауза LIMIT в изявлението за актуализиране. Забележете, ние правим имат клауза LIMIT.

Така че го правим в половин милион повторения на ред. Задава колона на произволно число между 1 и 20

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

Продължете да изпълнявате горното, докато няма camId е нула.

Пуснах го около 10 пъти (цялото отнема 7 до 10 минути)

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

Създайте полезен индекс (след вмъкванията, разбира се).

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

Създайте таблицата на кампуса.

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

Изпълнете двете заявки:

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

и

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

Така че времената са идентични. Изпълнявайте всеки десетина пъти.

EXPLAIN изходът е еднакъв и за двете

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

Използвайки функцията AVG(), получавам около 12% увеличение на производителността с псевдонима в having (с идентичен 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 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

И накрая, 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

Псевдонимът в had постоянно работи 35% по-бързо със същия EXPLAIN изход. Вижда се по-долу. Така че същият изход на Explain беше показан два пъти, че не води до една и съща производителност, а като обща улика.

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

Оптимизаторът изглежда предпочита псевдонима в притежаването в момента, особено за 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. проблем в отношенията много към много

  2. Как да конфигурирате репликация на източник-реплика в MySQL

  3. Как мога да сортирам резултат от mysql по списък с приоритетни идентификатори?

  4. Как мога да създам mysql db с Docker compose?

  5. Списък с ограничения от MySQL база данни