管理者が Web からクロールされた投稿を含む複数のニュースレターを作成する必要があるプロジェクトがあります。
クロールが完了したら、テーブルに投稿を挿入し、ソースを識別するため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;
すべての管理者 (ユーザー) は、1 つ以上の「フィード」にアクセスできます。そのため、ニュースレターの作成ページで、表示が許可されているフィードからの投稿のリストを表示したいと思います。また、ユーザーが以前にその投稿を選択した場合は、そのニュースレターの特定のカテゴリに投稿を配置するボタンを表示します。それを見せて、カテゴリから削除させてください。だから私もいくつかの他のテーブルを持っています: 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〜10kbsのデータが含まれているため、クエリを実行しようとすると(管理者がニュースレターやページネーションなどを作成するために頻繁に実行します)mysqlが表示されますこのエラー: 結合する行が多すぎるなどで、ほとんどの場合、本当に遅いです。
これらすべてを 1 つのクエリで実行する理由は、結果を 1 つの json レスポンスにして、追加のリクエストを行わなくてもユーザーにすばやく表示できるようにするためです。
このクエリを実行したり、インデックスなどを使用したりするためのより良い方法があるかどうかを知りたいです。よろしくお願いします。