我有一个项目,管理员需要创建多个通讯,其中包含一些来自网络的已抓取帖子。如何在大型表上优化这个mysql连接?
我在抓取完成后在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;
所以我用这个查询找到了允许的Feed职位,检查状态,如果帖子是在这个特定的通讯特定类别:
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〜10kbs的数据,所以有时当我尝试运行查询时(管理员经常运行这些查询以创建新闻简报,分页等)mysql显示这个错误:太多的行加入等等,大部分时间它真的很慢。
和我在一个查询中完成所有操作的原因是因为我希望结果在一个json响应中,因此我可以快速向用户显示它们而不会执行其他请求。
我想知道是否有更好的方法来做这个查询或使用索引或其他东西。 非常感谢您的帮助。
请粘贴说明计划 –
@SashiKant这是解释计划:http://d.pr/i/UKgh(帖子表包含〜2500行现在) – Sallar