MySQL добавление длинного текстового столбца делает запрос крайне медленным - есть совет по производительности? - PullRequest
0 голосов
/ 15 января 2020

У меня есть эта таблица с именем stories, в которой на данный момент находится 12 миллионов записей.

CREATE TABLE `stories` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `headline` varchar(255) DEFAULT NULL,
  `author_id` int(11) DEFAULT NULL,
  `body` longtext NOT NULL,
  `published_at` datetime DEFAULT NULL,
  `type_id` int(11) NOT NULL DEFAULT '0',
  `created_at` datetime DEFAULT NULL,
  `updated_at` datetime DEFAULT NULL,
  `aasm_state` varchar(255) NOT NULL,
  `deleted` tinyint(1) DEFAULT '0',
  `word_count` int(11) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`),
  UNIQUE KEY `index_stories_on_cms_story_id` (`cms_story_id`),
  KEY `typeid` (`type_id`),
  KEY `index_stories_on_published_at` (`published_at`),
  KEY `index_stories_on_updated_at` (`updated_at`),
  KEY `index_stories_on_aasm_state_and_published_at_and_deleted` (`aasm_state`,`published_at`,`deleted`),
  KEY `idx_author_id` (`author_id`)
) ENGINE=InnoDB AUTO_INCREMENT=511625276 DEFAULT CHARSET=utf8;

И я выполняю следующие запросы: (просто получение идентификатора работает нормально)

SELECT  `stories`.id 
  FROM `stories` 
 WHERE `stories`.`aasm_state` = 'scheduled'  
   AND `stories`.`deleted` = 0 
   AND (`stories`.`published_at` <= '2020-01-14 06:16:04') 
   AND (`stories`.`id` > 519492608)  
 ORDER 
    BY `stories`.`id` ASC 
  LIMIT 1000;
...
1000 rows in set (0.59 sec)

Однако, когда я добавляю к нему столбец длинного текста, я получаю:

mysql> SELECT  `stories`.id
, `stories`.body 
FROM `stories` 
WHERE `stories`.`aasm_state` = 'scheduled' 
AND `stories`.`deleted` = 0 
AND (`stories`.`published_at` <= '2020-01-14 06:16:04') 
AND (`stories`.`id` > 519492608)  
ORDER BY `stories`.`id` ASC LIMIT 1000;
...
1000 rows in set (6 min 34.11 sec)

Любой совет по производительности, как работать с этой таблицей?

Ответы [ 2 ]

2 голосов
/ 15 января 2020

Обычно реляционная СУБД применяется ORDER BY после получения начального набора результатов - поэтому ей нужно загрузить все эти истории, а затем отсортировать их. У меня нет доступа к вашему набору записей, но, по-моему, применение сортировки перед извлечением массового контента может повысить производительность:

SELECT *
FROM (
   SELECT  `stories`.id 
   FROM `stories` 
   WHERE `stories`.`aasm_state` = 'scheduled'  
   AND `stories`.`deleted` = 0 
   AND (`stories`.`published_at` <= '2020-01-14 06:16:04') 
   AND (`stories`.`id` > 519492608)  
   ORDER BY `stories`.`id` ASC 
   LIMIT 1000
) ids 
INNER JOIN stories bulk
ON ids.id=bulk.id

(Кстати, вы могли бы подумать о том, чтобы исследовать индексы больше - что вы положили тут выглядит довольно подозрительно).

0 голосов
/ 18 февраля 2020

Я рекомендую этот порядок для индекса:

INDEX(`aasm_state`,`deleted`,id)
  • сначала поставить = тесты
  • в конце диапазона, соответствующего ORDER BY; надеюсь, это позволит избежать необходимости собирать много строк и сортировать их перед тем, как перейти к LIMIT.

Этот индекс может помочь всем вариантам запроса.

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