大量のデータ量のためのMySQLページングクエリ最適化スキーム

方法1:データベースが提供するSQLステートメントを直接使用する

ステートメントスタイル:  MySQLでは、次のメソッドを使用できます。

SELECT * FROM 表名称 LIMIT M,N

シーンに適応: 少量のデータ(数百/数千)の状況に適しています

理由/欠点: 全表スキャン、速度が非常に遅くなり、一部のデータベース結果セットが不安定に戻ります(たとえば、1、2、3を一度に返し、2、1、3を一度に返すなど)。制限は結果セットから制限されますMの位置でN出力を取り出し、残りを破棄します。

 

方法2:主キーまたは一意のインデックスを作成し、インデックスを使用します(ページごとに10エントリを想定)

ステートメントスタイル:  MySQLでは、次のメソッドを使用できます。

SELECT * FROM 表名称 WHERE id_pk > (pageNum*10) LIMIT M

適応シナリオ:  大量のデータ(数万のタプル)がある状況に適しています

理由: インデックススキャン、速度は非常に高速になります。友人の提案:データクエリはpk_idに従って並べ替えられていないため、データが欠落している場合があり、方法3のみです

 

方法3:インデックスに基づいて並べ替え

ステートメントスタイル:  MySQLでは、次のメソッドを使用できます。

SELECT * FROM 表名称 WHERE id_pk > (pageNum*10) ORDER BY id_pk ASC LIMIT M

適応シナリオ: 大量のデータ(数万のタプル)がある状況に適しています。ORDERBYの後の列オブジェクトが主キーまたは一意であるため、インデックスによってORDERBY操作を排除できますが、結果セットは安定しています(安定した意味) 、方法1を参照)

理由: インデックススキャンは非常に高速になりますが、MySQLのソート操作はDESCを使用しないASCのみです(DESCは偽物であり、実際のDESCは将来行われる予定です...)。

 

方法4:インデックスに基づいて準備を使用する

最初の疑問符はpageNumを意味し、2番目の疑問符は?ページあたりのタプルの数を示します

ステートメントスタイル:  MySQLでは、次のメソッドを使用できます。

PREPARE stmt_name FROM SELECT * FROM 表名称 WHERE id_pk > (?* ?) ORDER BY id_pk ASC LIMIT M

シーンに適応: 大量のデータ

理由: インデックススキャン、速度は非常に高速になります。prepareステートメントは、一般的なクエリステートメントよりも少し高速です。

 

方法5:MySQLを使用してORDER操作をサポートすると、インデックスを使用していくつかのタプルをすばやく見つけ、全テーブルスキャンを回避できます

たとえば、1000〜1019行のタプルを読み取ります(pkは主キー/一意キーです)。

SELECT * FROM your_table WHERE pk>=1000 ORDER BY pk ASC LIMIT 0,20

方法6:「サブクエリ/結合+インデックス」を使用してタプルの位置をすばやく特定し、タプルを読み取ります。

例(idは主キー/一意キー、青いフォントの変数)

サブクエリの使用例:

SELECT * FROM your_table WHERE id <=
(SELECT id FROM your_table ORDER BY id desc LIMIT ($page-1)*$pagesize ORDER BY id desc
LIMIT $pagesize 

接続例を使用:

SELECT * FROM your_table AS t1
JOIN (SELECT id FROM your_table ORDER BY id desc LIMIT ($page-1)*$pagesize AS t2
WHERE t1.id <= t2.id ORDER BY t1.id desc LIMIT $pagesize; 

MySQLは、大量のデータに対して制限ページングを使用します。ページ数が増えると、クエリの効率が低下します。

 

テスト実験

1. limit startおよびcountページングステートメントを直接使用します。これは、私のプログラムでも使用されている方法です。

select * from product limit start, count 

開始ページが小さい場合、クエリにパフォーマンスの問題はありません。10、100、1000、10000(ページあたり20エントリ)からのページングの実行時間を見てみましょう。

次のように:

select * from product limit 10, 20   --0.016秒 
select * from product limit 100, 20  -- 0.016秒
select * from product limit 1000, 20  -- 0.047秒
select * from product limit 10000, 20   --0.094秒

開始レコードが増加するにつれて、時間も増加することがわかりました。これは、ページングステートメントの制限が開始ページ番号に大きく関係していることを示しています。次に、開始レコードを40wに変更してそれを調べます(つまり、レコード一般に)

select * from product limit 400000, 20   --3.229秒 

レコードの最後のページを取得した時間を見てください

select * from product limit 866613, 20   --37.44秒 

明らかに、この種のページングの最大のページ番号ページでは、この種の時間は耐えられません。

これから、2つのことを要約することもできます。

  • 制限ステートメントのクエリ時間は、開始レコードの位置に比例します

  • mysqlの制限ステートメントは非常に便利ですが、多くのレコードがあるテーブルで直接使用するのには適していません。

 

2.制限ページング問題のパフォーマンス最適化方法

テーブルのカバリングインデックスを使用してページングクエリを高速化する

インデックスクエリを使用するステートメントにインデックス列(カバーするインデックス)のみが含まれている場合、この場合のクエリは非常に高速になることは誰でも知っています。

インデックス検索用に最適化されたアルゴリズムがあり、データがクエリインデックス上にあるため、関連するデータアドレスを見つける必要がなく、多くの時間を節約できます。さらに、Mysqlには関連するインデックスキャッシュがありますが、同時実行性が高い場合はキャッシュを使用することをお勧めします。

この例では、idフィールドが主キーであることを認識しているため、当然ながらデフォルトの主キーインデックスが含まれています。ここで、カバリングインデックスを使用してクエリの効果を見てみましょう。

今回は、次のように、最後のページのデータをクエリします(id列のみが含まれるカバリングインデックスを使用)。

select id from product limit 866613, 20 0.2秒 

すべての列を照会する37.44秒と比較すると、約100倍高速です。

したがって、すべての列を照会する場合は、2つの方法があり、1つはid> =の形式で、もう1つは結合を使用する方法です。実際の状況を見てください。

SELECT * FROM product WHERE ID > =(select id from product limit 866613, 1) limit 20

クエリ時間は0.2秒です。

 

別の書き方

SELECT * FROM product a JOIN (select id from product limit 866613, 20) b ON a.ID = b.id

クエリ時間も非常に短いです!

3.複合インデックスの最適化方法

MySqlのパフォーマンスはどのくらい高くなりますか?MySqlは間違いなくdbaレベルのマスターがプレイするのに適したデータベースです。通常、10,000のニュース記事を含む小さなシステムを作成できます。xxフレームワークを使用すると、迅速な開発を実現できます。

しかし、データの量が10万、数百万から数千万に達した場合、彼のパフォーマンスはそれほど高くなるでしょうか?少し間違えるとシステム全体が書き換えられたり、システムが正常に動作しなくなったりすることがあります!さて、それほどナンセンスではありません。

 

事実について話し、例を見てください:

データテーブルcollect(id、title、info、vtype)には次の4つのフィールドがあります。titleは固定長、infoはテキスト、idは段階的、vtypeはtinyint、vtypeはインデックスです。

これは、基本的なニュースシステムの単純なモデルです。データを入力して、10万件のニュースを入力します。最後に、収集は100,000レコードであり、データベーステーブルはハード1.6Gを占有します。

次のSQLステートメントを見てください。

select id,title from collect limit 1000,10;

すぐに、基本的には0.01秒で問題ありません。次に以下を見てください。

select id,title from collect limit 90000,10;

ページングは​​90,000から始まり、結果は?

完了するまで8〜9秒ですが、私の神の何が問題になっていますか?実際、このデータを最適化するには、オンラインで答えを見つけてください。次のステートメントを見てください。

select id from collect order by id limit 90000,10;

まもなく、0.04秒で問題ありません。どうして?id主キーはインデックス作成に使用されるため、もちろん高速です。

オンライン改革は次のとおりです。

select id,title from collect where id>=(select id from collect order by id limit 90000,1) limit 10;

これは、IDを使用したインデックス付けの結果です。しかし、問題が少し複雑であれば、それで終わりです。次のステートメントを見てください

select id from collect where vtype=1 order by id limit 90000,10; 

非常に遅く、8〜9秒かかりました。

私がここに来ると、私は多くの人が私が壊れているように感じると思います!vtypeはインデックス付けされていますか?どうして遅いの?vtypeインデックスは良いです、あなたは直接

select id from collect where vtype=1 limit 1000,10;

非常に高速で、基本的には0.05秒ですが、90倍に増加し、90,000から始まり、0.05 * 90 = 4.5秒の速度です。そして、テスト結果は8〜9秒で1桁に達しました。

 

ここから、誰かがサブテーブルのアイデアを提案しました、これはdis #cuzフォーラムと同じアイデアです。アイデアは次のとおりです。

インデックステーブルを作成します。t(id、title、vtype)を固定長に設定し、ページングを実行すると、結果がページアウトされて収集された情報が検索されます。実現可能ですか?実験の下であなたは知るでしょう。

100,000レコードがt(id、title、vtype)に格納され、データテーブルのサイズは約20Mです。使用する

select id from t where vtype=1 order by id limit 90000,10;

すぐに。基本的に、0.1〜0.2秒で実行できます。これはなぜですか?

収集するデータが多すぎるためか、ページングは​​長い道のりになると思います。この制限は、データテーブルのサイズに完全に関連しています。実際、これはまだ全表スキャンです。データ量が少ないからといって、100,000しか高速ではありません。では、クレイジーな実験をしてみましょう。100万を追加してパフォーマンスをテストします。データを10回追加した後、tテーブルはすぐに200Mを超え、固定長でした。それでも今のクエリステートメントでは、完了するまでの時間は0.1〜0.2秒です。サブメーターのパフォーマンスに問題はありませんか?

違う!私たちの制限はまだ90,000なので、非常に高速です。大きなものを与える、900,000から開始

select id from t where vtype=1 order by id limit 900000,10;

結果を見てください。時間は1〜2秒です。どうして?

サブテーブルが完成してからまだ長い間、非常に憂鬱です。固定長は制限のパフォーマンスを向上させると言う人もいますが、最初はレコードの長さが固定されているので、mysqlは900,000の位置を計算できるはずだと思いました。しかし、mysqlのインテリジェンスを過大評価しましたが、これは商用データベースではないため、固定長と非固定長は制限にほとんど影響しないことが判明しました。100万レコードに達した後、discuzが非常に遅くなると言う人がいるのも不思議ではありません。これは本当だと思います。これはデータベース設計に関連しています!

MySQLは100万の制限を超えることはできませんか?100万ページに達したとき、それは本当に限界ですか?

答えは次のとおりです。なぜ100万を超えることができないのかは、mysqlを設計していないことが原因です。非分割テーブル方式を紹介して、クレイジーなテストをしましょう!1つのテーブルで100万件のレコードと10Gデータベースを処理し、ページングを迅速に行う方法!

さて、テストは収集テーブルに戻り、テストの結論は次のとおりです。

300,000データ、サブテーブルメソッドを使用することが可能であり、300,000を超える速度は、あなたがそれを我慢できないほど遅くなります!もちろん、サブテーブル+ meメソッドを使用する場合、それは完璧です。しかし、私の方法を使用した後、サブテーブルなしで完全に解決できます!

答えは、複合インデックスです。mysqlインデックスを設計しているときに、インデックス名を自由に選択でき、いくつかのフィールドを選択できることを偶然発見しました。

はじまり

select id from collect order by id limit 90000,10; 

インデックスがなくなっているのでとても高速ですが、どこに追加してもインデックスは取得されません。試してみるという考えでsearch(vtype、id)のようなインデックスを追加しました。

次にテストする

select id from collect where vtype=1 limit 90000,10; 

とても早い!0.04秒で完了!

もう一度テストします。

select id ,title from collect where vtype=1 limit 90000,10; 

残念ながら、8〜9秒、検索インデックスはありません!

もう一度テストします。この文を検索(id、vtype)、または選択します。これも非常に残念です、0.5秒。

要約すると、where条件があり、インデックスに制限を使用する場合は、インデックスを設計する必要があります。最初にwhereを配置し、次に主キーがlimitで使用されるようにすると、主キーのみを選択できます。

ページングの問題は完全に解決されています。IDをすばやく返すことができる場合は、制限を最適化する可能性があります。このロジックによれば、100万レベルの制限を0.0x秒以内に分割する必要があります。mysqlステートメントの最適化とインデックス付けは非常に重要であるようです!

 

おすすめ

転載: blog.csdn.net/bj_chengrong/article/details/103233267