Как сохранить время запроса Laravel SQl менее 5 секунд - PullRequest
1 голос
/ 11 июня 2019

Мое php-приложение использует laravel 4.1.31. Для запросов к базе данных он использует библиотеку knockout js через ajax. Когда размер базы данных увеличивается, загрузка ajax становится проблемой, потому что она занимает слишком много времени и иногда останавливается на полпути. Я не знаком с библиотеками, поэтому не могу выполнить оптимизацию на уровне приложения.

Я надеюсь, что смогу оптимизировать запрос к базе данных и держать каждый запрос менее 5 секунд.

Вот некоторая информация, которой я могу поделиться:

RAM: 2 ГБ 1core Debian 9. Одиночная база данных Innodb.

Журнал медленных запросов:

# Time: 190611  7:49:08
# User@Host: user[user] @ localhost []
# Thread_id: 690728  Schema: user  QC_hit: No
# Query_time: 9.343611  Lock_time: 0.000030  Rows_sent: 100  Rows_examined: 440481
# Rows_affected: 0
use user;
SET timestamp=1560239348;
select * from `titles` where `titles`.`type` = 'movie'
       order by `tmdb_rating` desc limit 100 offset 86500;

ПОКАЗАТЬ CREATE TABLE заголовки;

CREATE TABLE `titles` (
 `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
 `title` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
 `type` enum('movie','series') COLLATE utf8_unicode_ci DEFAULT NULL,
 `imdb_rating` varchar(10) COLLATE utf8_unicode_ci DEFAULT NULL,
 `tmdb_rating` varchar(10) COLLATE utf8_unicode_ci DEFAULT NULL,
 `mc_user_score` varchar(10) COLLATE utf8_unicode_ci DEFAULT NULL,
 `mc_critic_score` smallint(5) unsigned DEFAULT NULL,
 `mc_num_of_votes` int(10) unsigned DEFAULT NULL,
 `imdb_votes_num` bigint(20) unsigned DEFAULT NULL,
 `release_date` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
 `year` smallint(5) unsigned DEFAULT NULL,
 `plot` text COLLATE utf8_unicode_ci,
 `genre` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
 `tagline` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
 `poster` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
 `background` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
 `awards` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
 `runtime` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
 `trailer` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
 `budget` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
 `revenue` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
 `views` bigint(20) NOT NULL DEFAULT '1',
 `tmdb_popularity` float(50,2) unsigned DEFAULT NULL,
 `imdb_id` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
 `tmdb_id` bigint(20) unsigned DEFAULT NULL,
 `season_number` tinyint(3) unsigned DEFAULT NULL,
 `fully_scraped` tinyint(3) unsigned NOT NULL DEFAULT '0',
 `allow_update` tinyint(3) unsigned NOT NULL DEFAULT '1',
 `featured` tinyint(3) unsigned NOT NULL DEFAULT '0',
 `now_playing` tinyint(3) unsigned NOT NULL DEFAULT '0',
 `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
 `updated_at` timestamp NULL DEFAULT NULL,
 `temp_id` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
 `language` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
 `country` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
 `original_title` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
 `affiliate_link` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
 `custom_field` text COLLATE utf8_unicode_ci,
 PRIMARY KEY (`id`),
 UNIQUE KEY `titles_imdb_id_unique` (`imdb_id`),
 UNIQUE KEY `titles_tmdb_id_type_unique` (`tmdb_id`,`type`),
 KEY `titles_mc_num_of_votes_index` (`mc_num_of_votes`),
 KEY `titles_created_at_index` (`created_at`),
 KEY `titles_release_date_index` (`release_date`),
 KEY `titles_title_index` (`title`),
 KEY `titles_mc_user_score_index` (`mc_user_score`),
 KEY `titles_tmdb_popularity_index` (`tmdb_popularity`),
 KEY `titles_temp_id_index` (`temp_id`),
 KEY `titles_tmdb_rating_index` (`tmdb_rating`)
) ENGINE=InnoDB AUTO_INCREMENT=18712721 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci

ОБЪЯСНИТЬ выберите * из titles, где titles. type = 'фильм' заказ по смещению tmdb_rating предел 100 desc 86500;

+------+-------------+--------+------+---------------+------+---------+------+--------+-----------------------------+
| id   | select_type | table  | type | possible_keys | key  | key_len | ref  | rows   | Extra                       |
+------+-------------+--------+------+---------------+------+---------+------+--------+-----------------------------+
|    1 | SIMPLE      | titles | ALL  | NULL          | NULL | NULL    | NULL | 311859 | Using where; Using filesort |
+------+-------------+--------+------+---------------+------+---------+------+--------+-----------------------------+
1 row in set (0.01 sec)

my.cnf Настройки:

default-storage-engine = InnoDB
symbolic-links=0
skip-external-locking
max_allowed_packet = 16M
table_open_cache = 5000
query_cache_size = 0
query_cache_type = 0
thread_cache_size = 4
tmp_table_size = 256M
max_heap_table_size = 256M
performance_schema = ON
key_buffer_size = 140k
sort_buffer_size = 256K
read_buffer_size = 128K
read_rnd_buffer_size = 256k
myisam_sort_buffer_size = 140k
join_buffer_size = 2M

innodb_file_per_table
innodb_buffer_pool_size = 512M
innodb_log_file_size = 200M
innodb_buffer_pool_instances = 1
innodb_write_io_threads = 4
innodb_read_io_threads = 4
innodb_thread_concurrency = 4
innodb_flush_method = O_DIRECT
innodb_log_buffer_size = 32M
innodb_io_capacity = 1000
innodb_io_capacity_max = 3000
sync_binlog = 1

max_connections=100
max_user_connections=100
wait_timeout=10
interactive_timeout=30
long_query_time=5
slow-query-log =1
slow-query-log-file = /var/log/mysql/mysql-slow.log

Использование памяти:

Private  +   Shared  =  RAM used       Program

224.0 KiB +  26.5 KiB = 250.5 KiB       agetty (2)
248.0 KiB +  41.0 KiB = 289.0 KiB       sftp-server
180.0 KiB + 124.0 KiB = 304.0 KiB       anvil
404.0 KiB +  31.5 KiB = 435.5 KiB       vsftpd
392.0 KiB + 104.5 KiB = 496.5 KiB       dovecot
564.0 KiB +  39.5 KiB = 603.5 KiB       memcached
484.0 KiB + 122.0 KiB = 606.0 KiB       log
828.0 KiB +  44.0 KiB = 872.0 KiB       systemd-udevd
968.0 KiB +  42.0 KiB =   1.0 MiB       ntpd
732.0 KiB + 307.0 KiB =   1.0 MiB       systemd-logind
684.0 KiB + 355.0 KiB =   1.0 MiB       sh (8)
340.0 KiB + 754.0 KiB =   1.1 MiB       vesta-nginx (2)
  1.0 MiB +  58.5 KiB =   1.1 MiB       dbus-daemon
880.0 KiB + 250.5 KiB =   1.1 MiB       auth
760.0 KiB + 496.0 KiB =   1.2 MiB       flock (6)
  1.2 MiB + 244.0 KiB =   1.4 MiB       config
  1.7 MiB + 205.5 KiB =   1.9 MiB       systemd-journald
  1.9 MiB +  47.0 KiB =   1.9 MiB       rsyslogd
  2.1 MiB + 103.0 KiB =   2.2 MiB       exim4
  2.5 MiB +  76.0 KiB =   2.6 MiB       bash
  2.5 MiB +   1.3 MiB =   3.8 MiB       cron (9)
  2.2 MiB +   2.1 MiB =   4.3 MiB       sshd (4)
  2.2 MiB +   2.1 MiB =   4.4 MiB       nginx (3)
500.0 KiB +   4.8 MiB =   5.2 MiB       vesta-php (3)
  4.3 MiB +   3.7 MiB =   7.9 MiB       systemd (5)
 15.2 MiB + 109.5 KiB =  15.3 MiB       fail2ban-server
 67.3 MiB +  15.4 MiB =  82.6 MiB       php7.0 (8)
100.9 MiB +  67.2 MiB = 168.1 MiB       apache2 (12)
758.7 MiB + 156.0 KiB = 758.9 MiB       mysqld

Команда TOP:

top - 14:10:43 up 7 days, 23:12,  1 user,  load average: 0.79, 0.91, 0.69
Tasks: 145 total,   4 running, 141 sleeping,   0 stopped,   0 zombie
%Cpu(s): 19.1 us,  6.0 sy,  0.0 ni, 71.9 id,  2.7 wa,  0.0 hi,  0.3 si,  0.0 st
KiB Mem :  2052588 total,   501496 free,  1085916 used,   465176 buff/cache
KiB Swap:        0 total,        0 free,        0 used.   735980 avail Mem

  PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND
23688 mysql     20   0 1211616 770288      0 S  7.3 37.5 543:04.35 mysqld
29889 admin     20   0  539584  53996  38624 R  3.7  2.6   0:00.74 apache2
27140 www-data  20   0  537900  64576  50864 S  3.0  3.1   0:10.99 apache2
29901 admin     20   0  539484  53356  38100 S  2.3  2.6   0:00.71 apache2
29972 admin     20   0  538404  46336  32220 S  2.3  2.3   0:00.24 apache2
29297 admin     20   0  539572  64000  48648 S  2.0  3.1   0:02.00 apache2
30084 www-data  20   0  536388  43876  31700 S  1.3  2.1   0:00.24 apache2
30063 admin     20   0  392344  34440  21948 S  1.0  1.7   0:00.54 php
30042 admin     20   0  311432  30956  21628 S  0.7  1.5   0:00.10 php
30347 root      20   0   44888   3616   3016 R  0.7  0.2   0:00.04 top
    7 root      20   0       0      0      0 R  0.3  0.0   8:52.43 rcu_sched
 4834 root      20   0       0      0      0 S  0.3  0.0   0:01.46 kworker/u2:2
23741 memcache  20   0  335680    424      0 S  0.3  0.0   2:41.11 memcached
29002 www-data  20   0  537740  70296  56792 S  0.3  3.4   0:03.03 apache2
29279 www-data  20   0  537504  59164  45840 S  0.3  2.9   0:01.75 apache2
29709 root      20   0       0      0      0 S  0.3  0.0   0:00.07 kworker/0:0
    1 root      20   0  204556   4732   3076 S  0.0  0.2   0:21.00 systemd
    2 root      20   0       0      0      0 S  0.0  0.0   0:00.01 kthreadd
    3 root      20   0       0      0      0 R  0.0  0.0   8:12.40 ksoftirqd/0

Пример еще одного медленного запроса:

# Query_time: 21.742335  Lock_time: 0.000042  Rows_sent: 0  Rows_examined: 354027
# Rows_affected: 0
SET timestamp=1560293586;
select * from `titles`
    where `titles`.`type` = 'movie'
      and ( select count(*)
            from `actors`
            inner join `actors_titles` on `actors`.`id` = `actors_titles`.`actor_id`
            where `actors_titles`.`title_id` = `titles`.`id`
              and `name` like 'teren' 
          ) >= 1
    order by `mc_num_of_votes` asc
    limit 100 offset 0;

1 Ответ

1 голос
/ 11 июня 2019

тьфу: limit 100 offset 86500

Не делай так нумерацию страниц. Вместо этого «помните, где вы остановились». Недостатком этого является отсутствие «перехода на страницу 864», но кто это делает. А кто делает следующее-следующее-следующее ... 865 раз?

Дальнейшее обсуждение этой распространенной проблемы: http://mysql.rjweb.org/doc.php/pagination

И в нем более подробно рассмотрено «оставленное» решение.

Другая потенциальная проблема: order by tmdb_rating desc - Возможно, несколько названий имеют одинаковый «рейтинг»? Если да, то в каком порядке вы хотите перечислить названия? Простой ответ - указать какой-то однозначный (но несколько произвольный) порядок: order by tmdb_rating desc, id desc.

Помнить, где вы остановились в сложном порядке, сложнее, но возможно.

Другие примечания:

  • WHERE type=... ORDER BY rating может извлечь выгоду из «составного» * ​​1022 *, в этом порядке.

  • 3 уникальных клавиши звучат неправильно.

  • 2 извлекаемые столбцы TEXT ухудшают производительность. Не делайте SELECT *, если вам не нужны все столбцы.

  • tmp_table_size = 256M и max_heap_table_size = 256M опасно высоки для крошечных 2 ГБ оперативной памяти. Сократите их до 1% ОЗУ.

  • Вместо ( SELECT COUNT(*) FROM...) >=1, сделайте EXISTS ( SELECT 1 FROM ...)

...