5

私のテーブル

Field   Type    Null    Key Default Extra
id      int(11)     NO  PRI NULL    auto_increment
userid  int(11)     NO  MUL NULL     
title   varchar(50) YES     NULL     
hosting varchar(10) YES     NULL     
zipcode varchar(5)  YES     NULL     
lat     varchar(20) YES     NULL     
long    varchar(20) YES     NULL     
msg    varchar(1000)YES MUL NULL     
time    datetime    NO      NULL     

それがテーブルです。500k 行のデータをシミュレートし、ランダムに 270k 行を削除して、500k の自動インクリメントで 230k だけを残しました。

これが私のインデックスです

Keyname Type    Unique  Packed  Field   Cardinality Collation   Null
PRIMARY BTREE   Yes No  id            232377    A       
info    BTREE   No  No  userid          2003    A       
lat                                    25819    A   YES
long                                   25819    A   YES
title                                  25819    A   YES
time                                   25819    A   

それを念頭に置いて、ここに私のクエリがあります:

SELECT * FROM postsWHERE long>-118.13902802886 AND long<-118.08130797114 AND lat>33.79987197114 AND lat<33.85759202886 ORDER BY ID ASC LIMIT 0, 25

行 0 ~ 15 を表示しています (合計 16、クエリに 1.5655 秒かかりました) [id: 32846 - 540342]

クエリでは 1 ページしか表示されませんでしたが、230,000 件のレコードすべてを検索する必要があったため、それでも 1.5​​ 秒かかりました。

説明されているクエリは次のとおりです。

id  select_type table   type    possible_keys   key     key_len ref rows    Extra
1   SIMPLE      posts   index   NULL            PRIMARY 4       NULL 25     Using where

そのため、where 句を使用して 16 個の結果しか返さない場合でも、クエリの速度は遅くなります。

たとえば、より広範な検索を行う場合:

SELECT * FROM `posts` WHERE `long`>-118.2544681443 AND `long`<-117.9658678557 AND `lat`>33.6844318557 AND `lat`<33.9730321443 ORDER BY id ASC LIMIT 0, 25

行 0 ~ 24 を表示しています (合計 25、クエリにかかった時間は 0.0849 秒) [id: 691 - 29818]

20ページから最初のページを取得し、合計483ページが見つかった場合ははるかに高速ですが、25に制限しています.

しかし、最後のページを要求すると

SELECT * FROM `posts` WHERE `long`>-118.2544681443 AND `long`<-117.9658678557 AND `lat`>33.6844318557 AND `lat`<33.9730321443 ORDER BY id ASC LIMIT 475, 25

行 0 ~ 7 を表示しています (合計 8​​、クエリに 1.5874 秒かかりました) [id: 553198 - 559593]

遅いクエリを取得します。

私の質問は、どうすれば適切なページネーションを実現できますか? ウェブサイトが公開されると、投稿が削除され、毎日何百もの投稿が行われることを期待しています. 投稿は ID またはタイムスタンプで並べ替える必要があります。一部のレコードが削除されるため、ID は連続していません。標準のページネーションが欲しい

1 2 3 4 5 6 7 8 ... [Last Page]
4

7 に答える 7

2

句を使用して、以前のページに表示された結果レコードからフィルター処理しますWHERE。オフセットを指定する必要はなく、行数のみを指定します。たとえば、最後に表示された ID またはタイムスタンプを追跡し、それより大きい ID またはタイムスタンプを持つレコードのみをフィルタリングします。

于 2012-08-28T09:57:50.197 に答える
0

いくつかの発言。

あなたorder by idがいるとすると、それはあなたが最初と最後のレコードのIDを持っていることを意味するので、200000を制限するのではなく、id> $ last_id limit 20を使用する必要があり、それは非常に高速です。

欠点は、IDが連続していない(間に削除されている)場合、「最後の」ページまたはその間のページを提供できないことです。次に、最後の既知のIDとオフセット+制限の組み合わせを使用できます。

そして明らかに、適切なインデックスを持つことは、ソートと制限にも役立ちます。

于 2012-08-28T10:01:14.510 に答える
0

残念ながら、mysqlは30の結果を出力する前に、すべての20000行を読み取る必要があります[以前の並べ替え]。WHERE句内のインデックス付き列のフィルタリングを使用して検索を絞り込むことができる場合。

于 2012-08-28T10:00:30.663 に答える
0

主キーインデックスしかないようです。次のように、使用するフィールドにインデックスを定義することをお勧めします。

create index idx_posts_id on posts (`id` ASC);
create index idx_posts_id_timestamp on posts (`id` ASC, `timestamp` ASC);

プライマリ一意キーインデックスに加えて、キーフィールドに通常のインデックスを設定すると、通常、mysqlの速度が大幅に向上します。

于 2012-08-28T10:03:46.307 に答える
0

Mysqlは、大きなオフセットでかなりのパフォーマンスを失います: mysqlPerformanceブログから:

大きなLIMITに注意してください最初の数行が必要な場合は、インデックスを使用して並べ替えると効率的です。追加のフィルタリングが行われる場合でも、インデックスでさらに行をスキャンしてからLIMITで要求する必要があります。ただし、オフセット効率が大きいLIMITクエリを処理している場合は、問題が発生します。LIMIT 1000,10は、LIMIT0,10よりもはるかに遅い可能性があります。ほとんどのユーザーが結果で10ページを超えることはないのは事実ですが、検索エンジンボットはそうする可能性があります。私のプロジェクトでボットが200ページ以上を見ているのを見てきました。また、これに対処できない多くのWebサイトでは、DOS攻撃を開始するための非常に簡単なタスクが提供されます。少数の接続から多数のページを要求すれば十分です。他に何もしない場合は、ページ番号が大きすぎるリクエストをブロックしてください。

場合によっては、たとえば、結果が静的である場合は、結果を事前に計算して、位置を照会できるようにすることが理にかなっている場合があります。したがって、LIMIT 1000,10でクエリを実行する代わりに、1000から1009までのWHERE位置があり、どの位置でも同じ効率が得られます(インデックスが付けられている限り)。

于 2012-08-28T10:03:59.297 に答える
0

AUTO INCREMENTを使用している場合は、以下を使用できます。

SELECT * FROM投稿 WHEREIDID >= 200000 ORDER BY_DESC LIMIT 200000 , 30

このように、mysqlは200000を超える行のみをトラバースする必要があります。

于 2012-08-28T10:08:14.037 に答える
0

私はそれを考え出した。私を遅らせていたのは注文です。私は制限を呼び出し、さらに下に行くように要求したので、ソートする必要がありました。それで、サブクエリを追加して、最初にWERE 節で必要なデータを抽出してから、使用ORDER BYして修正しましたLIMIT

SELECT * FROM 
    (SELECT * from `posts` as `p` 
        WHERE 
           `p`.`long`>-119.2544681443 
           AND `p`.`long`<-117.9658678557 
           AND `p`.`lat`>32.6844318557 A
           ND `p`.`lat`<34.9730321443  

    ) as posttable 
    order by id desc 
    limit x,n

それを行うことで、次のことを達成しました。

id  select_type     table        type   possible_keys   key key_len ref     rows    Extra
1   PRIMARY         <derived2>   ALL    NULL            NULL NULL   NULL    3031    Using filesort
2   DERIVED         p            ALL    NULL            NULL NULL   NULL    232377  Using where

ここで、「where」と orderby のみを使用して 232k の結果をフィルタリングし、3031 の結果を制限します。

行 0 ~ 3030 を表示しています (合計 3,031、クエリにかかった時間は 0.1431 秒)

于 2012-08-28T23:56:22.473 に答える