18

私は2つのテーブルを持っています。1つはユーザーIDに主キーを持つユーザーテーブルで、もう1つは外部キーを持つユーザーテーブルを参照します。

Userテーブルには(今のところ)1つのエントリしかなく、もう1つのテーブルには100万のエントリがあります。

次の参加は私を怒らせます:

 SELECT p0_.*, p1_.*
 FROM photo p0_, User p1_
 WHERE p0_.user_id = p1_.user_id
 ORDER BY p0_.uploaddate DESC Limit 10 OFFSET 100000

クエリは、順序が指定されている非常に高速なマシンで12秒かかり、順序が指定されていない場合は0.0005秒かかります。

user_id(IDX_14B78418A76ED395)にインデックスがあり、user_idとuploaddateに複合インデックス( "search2")があります。

EXPLAINは次のことを示しています。

+----+-------------+-------+------+------------------------------+----------------------+---------+---------------------+-------+---------------------------------+
| id | select_type | table | type | possible_keys                | key                  | key_len | ref                 | rows  | Extra                           |
+----+-------------+-------+------+------------------------------+----------------------+---------+---------------------+-------+---------------------------------+
|  1 | SIMPLE      | p1_   | ALL  | PRIMARY                      | NULL                 | NULL    | NULL                |     1 | Using temporary; Using filesort |
|  1 | SIMPLE      | p0_   | ref  | IDX_14B78418A76ED395,search2 | IDX_14B78418A76ED395 | 4       | odsfoto.p1_.user_id | 58520 |                                 |
+----+-------------+-------+------+------------------------------+----------------------+---------+---------------------+-------+---------------------------------+

テーブル定義:

CREATE TABLE `photo` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`album_id` int(11) DEFAULT NULL,
`exif_id` int(11) DEFAULT NULL,
`title` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
`width` int(11) NOT NULL,
`height` int(11) NOT NULL,
`uploaddate` datetime NOT NULL,
`filesize` int(11) DEFAULT NULL,
`path` varchar(200) COLLATE utf8_unicode_ci NOT NULL,
`originalFilename` varchar(200) COLLATE utf8_unicode_ci NOT NULL,
`mimeType` varchar(200) COLLATE utf8_unicode_ci NOT NULL,
`description` longtext COLLATE utf8_unicode_ci,
`gpsData_id` int(11) DEFAULT NULL,
`views` int(11) DEFAULT NULL,
`likes` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `UNIQ_14B78418B0FC9251` (`exif_id`),
UNIQUE KEY `UNIQ_14B7841867E96507` (`gpsData_id`),
KEY `IDX_14B78418A76ED395` (`user_id`),
KEY `IDX_14B784181137ABCF` (`album_id`),
KEY `search_idx` (`uploaddate`),
KEY `search2` (`user_id`,`uploaddate`),
KEY `search3` (`uploaddate`,`user_id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;


CREATE TABLE `user` (
`user_id` int(11) NOT NULL,
`photoCount` int(11) NOT NULL,
`photoViews` int(11) NOT NULL,
`photoComments` int(11) NOT NULL,
`photoLikes` int(11) NOT NULL,
`username` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

このクエリを高速化するにはどうすればよいですか?

4

5 に答える 5

44

MySQLが後期行ルックアップを実行できないことに苦しんでいるようです。

これを試して:

SELECT  p.*, u.*
FROM    (
        SELECT  id
        FROM    photo
        ORDER BY
                uploaddate DESC, id DESC
        LIMIT   10
        OFFSET  100000
        ) pi
JOIN    photo p
ON      p.id = pi.id
JOIN    user u
ON      u.user_id = p.user_id
于 2013-01-16T21:58:56.110 に答える
2

2つの問題があります。

  1. INDEX(user_id, uploaddate)クエリの効率を大幅に向上させるを作成する必要があります。

  2. を使用するための回避策を見つける必要がありますLIMIT 10 OFFSET 100000。MySQLは100,000レコードを含むレコードセットを作成しており、最後の10レコードを最後から削除します...これは非常に非効率的です。

https://www.percona.com/blog/2006/09/01/mysql-order-by-limit-performance-optimization/

于 2013-01-16T21:45:51.033 に答える
1

に別のインデックスが必要ですuploaddate。このソートでは、uploaddateが最初の列である場合にのみ複合インデックスを利用します。user_idをORDERBYに追加することもできます。

    ....      
    ORDER BY p0_.user_id, p0_.uploaddate
于 2013-01-16T21:34:20.113 に答える
0

まず、結合せずに主キーに基づいて結果を取得し、結果を使用して結果を再度クエリします。
例:

$ userIds = mysql :: select( "select user_id from photo ORDER BY p0_.uploaddate DESC Limit 10 OFFSET 100000");

$ photoData = mysql :: select( "SELECT p0_。、p1_。FROM photo p0_、User p1_ WHERE p0_.user_id = p1_.user_id and p0_.user_id in($ userIds-> user_id)order by p0_.uploaddate");

ここでは、ステートメントを2つの部分に分割しました。1。
主キーに基づいて簡単に注文および取得でき、結合もありません。
2.IDと順序に基づいてクエリ結果を取得するのは限られた列のみであり、より短い時間でデータを取得できます

于 2017-01-27T18:21:14.533 に答える
-1

Quassnoi回答を使用して30秒から0.015秒/0.000秒まで!これは私がMySqlの専門知識と呼んだものです!私は自分の個人的なプロジェクトから1つの参加を切り取りました(それ自体との参加はありません)

Select ser.id_table, ser.id_rec, ser.relevance, cnt, title, description, sell_url, medium_thumb,  
        unique_id_supplier, keywords width, height, media_type 
from (    
        Select ser.id_rec, ser.id_table, ser.relevance, ser.cnt 
        from searchEngineResults ser     
        where thisSearch = 16287     
    order by  ser.relevance desc, cnt desc, id_rec 
    ) ser 
join photo_resell sou on sou.id = ser.id_rec 
#join searchEngineResults ser on ser.id_rec = tmp.id_rec 
limit 0, 9
于 2018-07-26T08:50:35.830 に答える