MySQLはクエリでORDER BYとLIMITをどのように処理しますか?


251

次のようなクエリがあります。

SELECT article FROM table1 ORDER BY publish_date LIMIT 20

ORDER BYはどのように機能しますか?すべてのレコードを注文してから最初の20件を取得しますか、それとも20件のレコードを取得してpublish_dateフィールドで注文しますか?

最後の記事である場合、最新の20件の記事を実際に取得できる保証はありません。


6
いくつかpublish_dateのsが等しい場合、それらによる順序LIMIT付けでは明確な結果が得られないことに注意してください。つまり、ページネーションに使用すると、異なるページに同じアイテムが表示される可能性があります。
Konrad Morawski 2013年

回答:


244

最初に注文してから、最初の20を取得します。データベースは、WHEREbefore句のすべてを処理しますORDER BY


1
だからタイミングは同じですか?
Yasar Arafath 2017年

7
違う!LIMIT壊れるORDER BY。戻って間違った結果。何らかの方法で返された結果セットを並べ替えますLIMITORDER BYLIMITORDER BY
Green

6
@グリーン、あなたは間違っている。説明については、これを読んでください。dev.mysql.com / doc / refman / 5.7 / en / limit-optimization.html ORDER BY列にインデックスが付けられている場合、レコードがLIMITがない場合とは異なる順序で返されることがあります。その列に同じ値を持つ1つ以上のレコード。
yitwail 2017

1
そのような問題に対する1つの迅速な解決策は、一意の値を持つことが望ましい列を1つ追加して、最初の列による順序の値が複数の行で同じである場合にデータベースが行の順序付けに関する一貫した規則を取得できるようにすることです。
rineez 2017

37

LIMIT句を使用すると、SELECTステートメントによって返される行数を制限できます。LIMITは1つまたは2つの数値引数を取ります。これらは両方とも負でない整数定数でなければなりません(準備済みステートメントを使用する場合を除く)。

2つの引数を使用して、最初の引数は最初に返される行のオフセットを指定し、2番目の引数は返される最大行数を指定します。最初の行のオフセットは0(1ではない)です。

SELECT * FROM tbl LIMIT 5,10; # Retrieve rows 6-15

特定のオフセットから結果セットの最後までのすべての行を取得するには、2番目のパラメーターに大きな数を使用できます。次のステートメントは、96行目から最後のすべての行を取得します。

SELECT * FROM tbl LIMIT 95,18446744073709551615;

引数が1つの場合、値は結果セットの先頭から返す行数を指定します。

SELECT * FROM tbl LIMIT 5; # Retrieve first 5 rows

つまり、LIMIT row_countはLIMIT 0、row_countと同等です。

詳細:http : //dev.mysql.com/doc/refman/5.0/en/select.html


5-14行目を取得していませんか?
Adonis K. Kakoulidis 2013年

@adonisいいえ、違います。この例は、MySQLドキュメント
抜粋です

番号5は6行目です。5行(0から4)は無視されます。
Phil Perry

1
ただし、ORDER BYなしでLIMITを使用すると、一貫性のない結果が生じる可能性があります。残念ながら、LIMITを適用する前に結果セット全体を順序付けする必要があります。そうしないと、DBMSが自由に結果を順序付けしてから、そのセットに対してOFFSETとLIMITを自由に順序付けできます。これは、DBMSがOFFSETとLIMITに基づいて代替のクエリプランを選択したため、任意の順序が原因である可能性があることを読みました。
Barton

4
質問は、制限と注文を要求しています。しかし、答えはこの質問とはまったく関係ありません
シェンリャン2017年

9

@Jamesが言うように、すべてのレコードを並べ替え、最初の20行を取得します。

そのため、最初に公開された20件の記事を確実に取得できます。新しい記事は表示されません。

あなたの状況では、に追加descする ことをお勧めしますorder by publish_date。最新の記事が必要な場合は、最新の記事が最初になります。

結果を昇順で保持する必要があり、さらに最新の10件の記事のみが必要な場合は、mysqlに結果を2回ソートするように要求できます。

以下のこのクエリは、結果を降順で並べ替え、結果を10に制限します(つまり、括弧内のクエリ)。それでも降順で並べ替えられますが、満足できないため、mysqlにもう一度並べ替えるように依頼します。これで、最後の行に最新の結果があります。

select t.article 
from 
    (select article, publish_date 
     from table1
     order by publish_date desc limit 10) t 

order by t.publish_date asc;

すべての列が必要な場合は、次の方法で行います。

select t.* 
from 
    (select * 
     from table1  
     order by publish_date desc limit 10) t 

order by t.publish_date asc;

クエリを手動で記述してデータベースにさまざまなことを調べるときに、この手法を使用します。運用環境では使用していませんが、ベンチマークを行ったところ、余分な並べ替えはパフォーマンスに影響しません。


2
追加の並べ替えは、10行/アイテムのみに制限されているため、実質的にパフォーマンスに測定可能な影響を与えることはできません:-)。一般に、数百万の行があるか、DBMSがメモリに適合しないため結果セットをディスクにページングしている場合を除き(副選択が生成する)メモリ内テーブルのソートは非常に高速でほとんど測定できません(その場合) DBMSによっては、クエリを中止することもできます)。
Martin Kersten

7

適切なインデックス(この場合はpublish_dateフィールド)がある場合、MySQLはインデックス全体をスキャンして要求された20レコードを取得する必要はありません。20レコードはインデックスの先頭にあります。ただし、適切なインデックスがない場合は、テーブルのフルスキャンが必要になります。

これについては、2009年のMySQLパフォーマンスブログの記事があります


7

注文の最後に[asc]または[desc]を追加して、最も古いレコードまたは最新のレコードを取得できます

たとえば、最初に最新のレコードが表示されます

ORDER BY stamp DESC

LIMIT後に句を追加ORDER BY


3
Stackoverflowへようこそ。あなたはその質問を誤解したかもしれません。彼らは「並べ替えの方法」ではなく、操作の順序について尋ねていたと思います。(しかし、質問はすでに少し前に回答されているので、それは意味がないです。)
リー

5

このコードを使用できます SELECT article FROM table1 ORDER BY publish_date LIMIT 0,10 。0はレコードの開始制限&10レコード数です。


8
いいえ、必要ありません。 LIMIT 10はの省略形ですLIMIT 0,10
Lawrence Dol 2013年

2
はい、LIMIT 0,10には必要ありませんが、この制限のように要求できます
10,20

3

通常、LIMITは最後の操作として適用されるため、結果は最初にソートされてから20に制限されます。実際、ソートは最初の20のソート結果が見つかるとすぐに停止します。


11
2番目の文は最初の文に反します。最初の20件の結果が見つかったときにソートを停止することはできません。これは、前述のとおり、結果が返される前にソートが行われるためです。MySQLは、ソートが完了した後にのみ、最初の20件の結果を知ることができます。
トム

@Tom、実際にはそれが可能です(インデックス付きの列で並べ替える場合)。それはここで説明されています:dev.mysql.com/doc/refman/5.7/en/limit-optimization.html
yitwail

-3

また、LIMITの構文はデータベースによって異なります。次に例を示します。

mysql -制限1、2

postgres -リミット2オフセット1

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.