1

~100 万エントリの mySQL DB があります。

クエリを実行します。

SELECT a.id as aid, a.title as atitle, a.slug, summary, 
       a.link as alink, author, published, image, a.cat as acat, 
       a.rss as arss, a.site as asite 
  FROM articles a 
 ORDER BY published DESC 
 LIMIT 616150, 50;

読み込みに5分以上かかります。

私のテーブルとインデックス:

CREATE TABLE IF NOT EXISTS `articles` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `title` varchar(255) NOT NULL,
  `slug` varchar(255) NOT NULL,
  `summary` text NOT NULL,
  `link` text NOT NULL,
  `author` varchar(255) NOT NULL,
  `published` datetime NOT NULL,
  `image` text NOT NULL,
  `cat` int(11) NOT NULL,
  `rss` int(11) NOT NULL,
  `site` int(11) NOT NULL,
  `bitly` varchar(255) NOT NULL,
  `checked` tinyint(4) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`),
  UNIQUE KEY `title` (`title`),
  KEY `cat` (`cat`),
  KEY `published` (`published`),
  KEY `site` (`site`),
  KEY `rss` (`rss`),
  KEY `checked` (`checked`),
  KEY `id_publ_index` (`id`,`published`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1230234;

何を説明すると言う:

mysql> EXPLAIN EXTENDED SELECT a.id as aid, a.title as atitle, a.slug, summary, a.link as alink, author, published, image, a.cat as acat, a.rss as arss, a.site asite FROM 記事として ORDER BY 公開された DESC LIMIT 616150, 50;
+----+-------------+-------+-------+-------------- -------------+---------+------+--------+---------- +------+
| | ID | select_type | テーブル | タイプ | 可能な_キー | キー | key_len | 参照 | 行 | 行 フィルタリングされた | エクストラ |
+----+-------------+-------+-------+-------------- -------------+---------+------+--------+---------- +------+
| | 1 | シンプル | | | インデックス | ヌル | 公開 | 8 | ヌル | 616200 | 152.94 | | |
+----+-------------+-------+-------+-------------- -------------+---------+------+--------+---------- +------+
セット内の 1 行、1 警告 (0.46 秒)

このクエリを最適化する方法のヒントはありますか? mySQL が、要求された 50 行だけでなく、616200 行すべてを読み取る必要があるのはなぜですか?

お時間をいただきありがとうございます。

4

1 に答える 1

1

キーが使用されているのは、それがあなたpublishedが注文しているものだからです。このクエリはどのくらいの頻度で実行する必要がありますか?

このクエリをはるかに高速に実行するためにできる簡単な方法が 1 つあります。それは、publishedキーをより有効に活用することです。テーブルから取得する日付の範囲を定義するために使用WHEREします。

現在テーブルの 616,200 行を読み取っている理由は、インデックスを使用して範囲を制限していないためです。MySQL は、次の目的でフル インデックスを使用する必要があります。

  1. 最初の 616200行を DESC 順に並べ替えてから、
  2. 最後に、結果を 50 行に制限します。

可能であれば、別の方法でデータベースの結果をフィルタリングする必要があります。結果を WHERE に基づくように変更する (インデックスをより効率的に使用する) のが最も簡単な方法です。

例えば:

SELECT a.id as aid, a.title as atitle, a.slug, summary, 
       a.link as alink, author, published, image, a.cat as acat, 
       a.rss as arss, a.site as asite 
  FROM articles a 
 WHERE published > '2010-01-01'
 ORDER BY published DESC 
 LIMIT 6150, 50;

悲しいことに、ORDER BY と LIMIT はうまくスケーリングできず、すぐに速度が低下します。(たとえば、制限を に変更してから に変更し0, 50900000, 50速度がどのように影響を受けるかを確認します)、WHERE に情報を追加すると、クエリがはるかに高速になります。

編集:

日付で何を表示するかを知る方法がないため、どこに置くことはできません。さらに、このクエリは、... 秒ごとにニュースを収集するニュース アグリゲーターで実行されます。ページ分割された結果を作成できるように制限が設けられています。

新しい投稿を挿入しているため、LIMIT ステートメントにより、ユーザーがページを移動しているときにニュース項目がジャンプします。たとえば、1 ページ目にいて、[次へ] を押す前に 3 つの項目が追加された場合、[次へ]をクリックするまでに、前のページの最後の 3 つの項目が表示されます

可能な限り最高のユーザー エクスペリエンスを実現するには、最後に表示されたニュース アイテムの ID または最後に表示されたニュース アイテムの日付を何らかの形でページネーションに追加してみてください。これは、セッションまたはクエリ URL の一部によって実行できますが、インデックスをより有効に活用できます。

制限がある理由は理解しています。これは、一定量のページがヒットした後にクエリが遅くなる問題をどのように修正できるかということです。

速度の問題を効率的に修正するには、ページネーションの唯一の方法として「LIMIT」に依存するのではなく、インデックスをより有効に活用する必要があります。LIMIT は素晴らしいですが、日付で並べ替える必要があるため、目的の方法でレコードを取得するために最適化されていません。

あなたが言うように、「日付で何を表示するかを知る方法はありません」(少なくとも現在は...)アプリケーションがデータベースからフェッチする必要があるものを制限する方法が必要です。Facebook が結果を Facebook ウォールに表示するためだけに、Web サイトの個々の投稿のすべてのメンバーを調べる必要がないのと同じ方法です。より効率的にする方法を見つける必要があります。

于 2013-11-19T05:13:47.000 に答える