38

1:n の関係を介して 50 のフィードを含むテーブルにリンクされた、約 100.000 のブログ投稿を含むテーブルがあります。ポスティング テーブルの日時フィールドで並べ替えた select ステートメントを使用して両方のテーブルをクエリすると、MySQL は常にファイルソートを使用するため、クエリ時間が非常に遅くなります (>1 秒)。テーブルのスキーマは次のとおりですpostings(簡略化)。

+---------------------+--------------+------+-----+---------+----------------+
| Field               | Type         | Null | Key | Default | Extra          |
+---------------------+--------------+------+-----+---------+----------------+
| id                  | int(11)      | NO   | PRI | NULL    | auto_increment |
| feed_id             | int(11)      | NO   | MUL | NULL    |                |
| crawl_date          | datetime     | NO   |     | NULL    |                |
| is_active           | tinyint(1)   | NO   | MUL | 0       |                |
| link                | varchar(255) | NO   | MUL | NULL    |                |
| author              | varchar(255) | NO   |     | NULL    |                |
| title               | varchar(255) | NO   |     | NULL    |                |
| excerpt             | text         | NO   |     | NULL    |                |
| long_excerpt        | text         | NO   |     | NULL    |                |
| user_offtopic_count | int(11)      | NO   | MUL | 0       |                |
+---------------------+--------------+------+-----+---------+----------------+

そして、ここにfeedテーブルがあります:

+-------------+--------------+------+-----+---------+----------------+
| Field       | Type         | Null | Key | Default | Extra          |
+-------------+--------------+------+-----+---------+----------------+
| id          | int(11)      | NO   | PRI | NULL    | auto_increment |
| type        | int(11)      | NO   | MUL | 0       |                |
| title       | varchar(255) | NO   |     | NULL    |                |
| website     | varchar(255) | NO   |     | NULL    |                |
| url         | varchar(255) | NO   |     | NULL    |                |
+-------------+--------------+------+-----+---------+----------------+

実行に 1 秒以上かかるクエリを次に示します。post_dateフィールドにはインデックスがありますが、MySQL はそれを使用して posts テーブルをソートしていないことに注意してください。

SELECT 
    `postings`.`id`, 
    UNIX_TIMESTAMP(postings.post_date) as post_date, 
    `postings`.`link`, 
    `postings`.`title`, 
    `postings`.`author`, 
    `postings`.`excerpt`, 
    `postings`.`long_excerpt`, 
    `feeds`.`title` AS feed_title, 
    `feeds`.`website` AS feed_website
FROM 
    (`postings`)
JOIN 
    `feeds` 
ON 
    `feeds`.`id` = `postings`.`feed_id`
WHERE 
    `feeds`.`type` = 1 AND 
    `postings`.`user_offtopic_count` < 10 AND 
    `postings`.`is_active` = 1
ORDER BY 
    `postings`.`post_date` desc
LIMIT 
    15  

このクエリに対するコマンドの結果は、explain extendedMySQL がファイルソートを使用していることを示しています。

+----+-------------+----------+--------+---------------------------------------+-----------+---------+--------------------------+-------+-----------------------------+
| id | select_type | table    | type   | possible_keys                         | key       | key_len | ref                      | rows  | Extra                       |
+----+-------------+----------+--------+---------------------------------------+-----------+---------+--------------------------+-------+-----------------------------+
|  1 | SIMPLE      | postings | ref    | feed_id,is_active,user_offtopic_count | is_active | 1       | const                    | 30996 | Using where; Using filesort |
|  1 | SIMPLE      | feeds    | eq_ref | PRIMARY,type                          | PRIMARY   | 4       | feedian.postings.feed_id |     1 | Using where                 |
+----+-------------+----------+--------+---------------------------------------+-----------+---------+--------------------------+-------+-----------------------------+

パーツを削除するとorder by、MySQL はファイルソートの使用を停止します。このクエリを最適化して、MySQL でインデックスを使用してデータを並べ替えて選択する方法についてのアイデアがあれば教えてください。いくつかのブログ投稿で示唆されているように、すべての where/order by フィールドに結合インデックスを作成するなど、いくつかのことを既に試しましたが、これもうまくいきませんでした。

4

3 に答える 3

3

Also, it's important to remember that MySQL won't use an index if the column you're ordering by has a function applied to it.

You should also try aliasing postings.post_date as something else. This will tell MySQL to order by the unaltered column, and you'll still select the unix timestamp.

于 2009-08-25T05:41:53.037 に答える
3

MySQL には 2 つのファイルソート アルゴリズムがあります。ディスク上のレコードをソートする古いファイルソートと、メモリ内で動作する新しいバージョンです。

結合の最初のテーブルのインデックスを使用してクエリを並べ替えることができない場合は、ファイル並べ替えを実行する必要があります。固定幅形式に変換された並べ替え前の結果セットが並べ替えバッファーより大きい場合、またはテキスト フィールドが含まれている場合は、低速のディスク上のファイル並べ替えアルゴリズムを使用する必要があります (クエリにテキスト フィールドがあるため、2 番目の条件が満たされます)。 .

MySQL は is_active 列を使用することを選択しています。これは、表向きは列が他の結合および where 条件を続行する前に行を削除する際に最も選択的であると考えているためです。最初に提案することは、post_date、feed_id、および where 条件の列 (is_active、user_offtopic_count、post_date、feed_id) を使用して複合インデックスを作成することです。

于 2009-04-03T17:52:32.260 に答える