sql >> データベース >  >> RDS >> Mysql

mysql:非常に単純なSELECT id ORDER BY LIMITは、期待どおりにINDEXを使用しません(?!)

    インデックスルックアップはによるものです 、位置ではありません 。インデックスは値2955900を検索できますが、それを求めているわけではありません。テーブルの2955900行目のオフセットからクエリを開始するように要求しています。

    オプティマイザーは、すべての主キー値が連続していると想定することはできません。したがって、2955900番目の行の値はそれよりはるかに高い可能性があります。

    主キーの値が連続している場合でも、たとえば、行の45%にのみ一致するWHERE条件がある場合があります。この場合、2955900行目のID値は wayになります。 ID値2955900を過ぎています。

    つまり、ID値2955900のインデックスルックアップでは、2955900番目の行は配信されません。

    したがって、MySQLは制限のオフセットにインデックスを使用できません。 必須 行をスキャンして、offset+limit行に達するまでカウントします。

    MySQLには、LIMITに関連する最適化 があります。 、ただし、返される行数に達したらテーブルスキャンを停止することが重要です。オプティマイザは、EXPLAINプランで、可能性があると予想していると報告する場合があります。 テーブル全体をスキャンする必要があります。

    FORCEINDEX についてよくある誤解 インデックスの使用を強制するということです。 :-)実際、クエリができない インデックスを使用する(または、使用可能なインデックスがこのクエリにメリットがない場合)、FORCEINDEXは効果がありません。

    コメントを再確認してください:

    ページ付けは、データ駆動型Webアプリケーションの頻繁な悩みの種です。この機能は一般的ですが、最適化するのは簡単ではありません。ここにいくつかのヒントがあります:

    • なぜオフセット2955900でクエリを実行しているのですか?ユーザーがその数のページをふるいにかけることを本当に期待していますか?ほとんどのユーザーは、数ページ後にあきらめます(正確な数は、アプリケーションのタイプとデータによって異なります)。

    • クエリの数を減らします。ページネーション関数は、最初のページだけをユーザーに表示する場合でも、最初の5〜10ページをフェッチできます。ユーザーが数ページ進むことを想定して、他のページをキャッシュします。キャッシュされたページのセットを超えて進む場合にのみ、アプリは別のクエリを実行する必要があります。クライアントのブラウザでJavascriptの10ページすべてをキャッシュすることもできるので、[次へ]をクリックすると瞬時に 彼らのために(少なくとも最初の数ページのために)

    • 好奇心からクリックするので、ユーザーインターフェイスに[最後]ボタンを配置しないでください。 Googleには「次へ」ボタンがありますが「最後」ボタンはありません。そのため、UI自体が、オフセットの高い非効率的なクエリを実行することを思いとどまらせます。

    • ユーザーが一度に1ページずつ進む場合は、次のページのクエリのWHERE句で、前のページで返された最大のid値を使用します。つまり次の FORCE INDEXヒントがなくても、インデックスを使用します:

      SELECT * FROM thistable WHERE id > 544 LIMIT 20
      



    1. DB設計:すべての顧客に1つの大きなDBまたは多数の小さなDB

    2. PostgreSQL用のpt-pg-summaryPerconaToolkitの使用

    3. mysql経由でphpを実行しますか?

    4. 結果としてmysqlユニオンの列が間違っています