У меня есть проект, в котором администратору необходимо создать несколько информационных бюллетеней с некоторыми просканированными сообщениями из Интернета.
Я вставляю сообщения в таблицу posts
после завершения сканирования и назначаю им feed_id
для идентификации источника. это структура таблицы posts
(усеченная):
CREATE TABLE `posts` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`feed_id` int(11) NOT NULL,
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` timestamp NULL DEFAULT NULL,
`identifier` varchar(255) DEFAULT NULL,
`published` timestamp NULL DEFAULT NULL,
`content` longtext,
...
...
`is_unread` int(1) NOT NULL DEFAULT '1',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Каждый администратор (пользователь) имеет доступ к одному или нескольким каналам. Итак, на странице создания информационного бюллетеня я хочу показать им список сообщений из каналов, которые им разрешено просматривать, а также я показываю кнопку для размещения сообщений в определенных категориях этого информационного бюллетеня, если пользователь ранее выбрал это сообщение, я должен покажите ему это и пусть он удалит это из категории. Так что у меня есть и другие таблицы: newsletters
, categories
, newsletter_post
, category_post
. Вот их структуры:
newsletters
:
CREATE TABLE `newsletters` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` timestamp NULL DEFAULT NULL,
`sent_at` timestamp NULL DEFAULT NULL,
`title` varchar(255) DEFAULT NULL,
`date` date DEFAULT NULL,
`topic_id` int(11) NOT NULL,
`user_id` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
categories
:
CREATE TABLE `categories` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`topic_id` int(11) NOT NULL,
`title` varchar(255) DEFAULT NULL,
`slug` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
newsletter_post
:
CREATE TABLE `newsletter_post` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` timestamp NULL DEFAULT NULL,
`newsletter_id` int(11) NOT NULL,
`post_id` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
category_post
:
CREATE TABLE `category_post` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` timestamp NULL DEFAULT NULL,
`category_id` int(11) NOT NULL,
`post_id` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Итак, я использую этот запрос, чтобы найти сообщения для разрешенных каналов и проверить статус, если сообщение находится в определенной категории этого конкретного информационного бюллетеня:
SELECT DISTINCT `posts`.`id`, `published`, `posts`.`title`, `posts`.`content`, `source_name`, `category_id`, `newsletter_id`, `link_href`, categories.title as category_title
FROM `posts`
LEFT JOIN `category_post` ON `posts`.`id` = `category_post`.`post_id`
LEFT JOIN `categories` ON `categories`.`id` = `category_post`.`category_id`
LEFT JOIN `newsletter_post` ON `posts`.`id` = `newsletter_post`.`post_id`
LEFT JOIN `newsletters` ON `newsletters`.`id` = `newsletter_post`.`newsletter_id`
WHERE `feed_id` IN (6, 7) ORDER BY `posts`.`published` DESC LIMIT 40 OFFSET 0
но проблема в том, что это ужасно и не оптимизировано. Моя таблица posts
содержит до 50 000 строк каждый месяц, и каждая строка содержит в среднем 3–10 КБ данных, поэтому иногда, когда я пытаюсь выполнить запрос (который часто запускается администратором для создания информационного бюллетеня, разбивки на страницы и т. д.), mysql показывает эту ошибку: слишком много строк для объединения и т. д., и в большинстве случаев это очень медленно.
и причина, по которой я делаю все это в одном запросе, заключается в том, что я хочу, чтобы результат был в одном ответе json, чтобы я мог быстро показать им пользователя, не делая дополнительных запросов.
Я хочу знать, есть ли лучший способ выполнить этот запрос или использовать индексы или что-то еще. Заранее спасибо за вашу помощь.