MySQL - Почему такая разная производительность с отметками времени в этих 2 запросах? - PullRequest
2 голосов
/ 23 марта 2012

Я написал Perl-скрипт, который делает несколько SQL-запросов в таблице с более чем 140000 строками и расширяющейся.

Я хочу сравнить даты и получить несколько строк, но я понял, что, просто изменив один SQL-запрос, я получу так много разных скоростей выполнения.

Посмотрите на следующие результаты теста, выполняющие 100 $ sql запросов. Единственная строка, которую я изменяю в скрипте между различными выполнениями, это строка $ sql.

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

my $sql = "SELECT `mem_used`, `swap_used`, `mem_total` 
FROM `$config{db}{data_table}` 
WHERE  `host_id` = $host_id 
AND date >= '$date' 
AND TIMESTAMPDIFF( MINUTE , `date`, '$date' ) <= $interval;"; # VERY SLOW

time ./data_smoothing.pl

real    1m28.818s
user    1m6.516s
sys     0m0.256s

my $sql = "SELECT `mem_used`, `swap_used`, `mem_total` 
FROM `$config{db}{data_table}` 
WHERE  `host_id` = $host_id 
AND date >= '$date' 
AND (UNIX_TIMESTAMP(`date`) - UNIX_TIMESTAMP('$date')) <= ($interval * 60);"; #SLOW

$ time ./data_smoothing.pl

real    0m10.005s
user    0m0.108s
sys     0m0.028s

my $sql = "SELECT `mem_used`, `swap_used`, `mem_total` 
FROM `$config{db}{data_table}` 
WHERE  `host_id` = $host_id 
AND (`date` BETWEEN '$date' 
AND DATE_ADD('$date', INTERVAL $interval MINUTE));"; #FAST

$ time ./data_smoothing.pl

real    0m0.190s
user    0m0.084s
sys     0m0.016s

Как создается таблица (взято из mysqldump)

CREATE TABLE `data` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `host_id` smallint(6) NOT NULL,
  `date` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  `mem_total` double(10,3) DEFAULT NULL,
  `mem_used` double(10,3) DEFAULT NULL,
  `swap_total` double(10,3) DEFAULT NULL,
  `swap_used` double(10,3) DEFAULT NULL,
  `CPU_count` smallint(6) DEFAULT NULL,
  `load_avg_1` float DEFAULT NULL,
  `load_avg_5` float DEFAULT NULL,
  `load_avg_15` float DEFAULT NULL,
  `uptime` double(10,3) DEFAULT NULL,
  `cpuIdlingTime` double(10,3) DEFAULT NULL,
  `rxBytesTotal` bigint(20) DEFAULT NULL,
  `txBytesTotal` bigint(20) DEFAULT NULL,
  `rxPacketsTotal` bigint(20) DEFAULT NULL,
  `txPacketsTotal` bigint(20) DEFAULT NULL,
  PRIMARY KEY (`id`,`host_id`),
  KEY `fk_data_hosts` (`host_id`),
  KEY `date_memtot_hosts` (`date`,`mem_total`,`host_id`),
  CONSTRAINT `fk_data_hosts` FOREIGN KEY (`host_id`) REFERENCES `hosts` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=145300 DEFAULT CHARSET=utf8;

Ответы [ 3 ]

5 голосов
/ 23 марта 2012

Последний самый быстрый, потому что ваше сравнение хорошо подходит для индексации.Остальные, не так уж много.

Видите, когда вы вызываете функцию (или делаете что-то еще) со значением вашего столбца, прежде чем тестировать его, вы почти не можете использовать индекс для быстрого поиска соответствиястрок.Движок должен в основном пройти всю таблицу, взять дату, сделать с ней некоторую математику и затем проверить, выполняется ли условие.

Между тем, если вы просто скажете BETWEEN this_value AND that_value, MySQL вообще не обязан много делать - он может обратиться к индексу и просто найти две конечные точки диапазона, что намного быстрее.

Вызов DATE_ADD('$date', INTERVAL $interval MINUTE) не имеетсильно влияет на время выполнения, потому что MySQL, как правило, достаточно умен, чтобы кэшировать значения, которые он знает, не изменится, поэтому ему не нужно рассчитывать их снова каждый раз.

Что касается причины разницы междуПервые два, я не могу вам сказать.Возможно TIMESTAMPDIFF просто так медленно.Возможно, преобразование и математика намного проще с временными метками, особенно учитывая, что UNIX_TIMESTAMP('$date') не нужно пересчитывать каждый раз.Но все, что на самом деле только догадывается.

0 голосов
/ 25 июня 2013

Для версии TIMESTAMPDIFF порядок аргументов кажется неправильным. Чтобы получить положительный результат, второй аргумент должен быть последним из двух дат. Как написано, TIMESTAMPDIFF (MINUTE, date, '$ date') <= $ интервал всегда будет истинным. Поскольку будет возвращено больше строк результата, это может объяснить, почему производительность версии TIMESTAMPDIFF намного хуже, чем версия UNIX_TIMESTAMP. </p>

0 голосов
/ 23 марта 2012

Кажется, это проблема, связанная с индексированием. Можете ли вы опубликовать оператор создания таблицы, чтобы мы могли видеть ваши индексы?

Я знаю, что <или> не годятся для использования индексов, в то время как BETWEEN - это нормально ... вероятно, получая выгоду от первой даты, указанной в предложении BETWEEN. Все в DATE_ADD не будет использоваться для целей индексации (поскольку функции нарушают индексы)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...