1

すべてのフィルターが適用された SQL クエリは、10 lakhs (100 万) のレコードを返します。すべてのレコードを取得するには 76.28 秒かかります..これは許容できません。時間がかからない SQL クエリを最適化するにはどうすればよいですか。私が使用しているクエリは次のとおりです。

    SELECT cDistName , cTlkName, cGpName, cVlgName , 
           cMmbName , dSrvyOn 
      FROM sspk.villages 
 LEFT JOIN gps  ON nVlgGpID = nGpID
 LEFT JOIN TALUKS ON nGpTlkID = nTlkID   
 left JOIN dists ON nTlkDistID = nDistID
 LEFT JOIN HHINFO ON nHLstGpID = nGpID
 LEFT JOIN MEMBERS ON nHLstID = nMmbHhiID
 LEFT JOIN BNFTSTTS  ON nMmbID = nBStsMmbID
 LEFT JOIN STATUS ON nBStsSttsID = nSttsID
 LEFT JOIN  SCHEMES ON  nBStsSchID = nSchID
     WHERE (
               (nMmbGndrID = 1 and nMmbAge between 18 and 60) 
           or  (nMmbGndrID = 2 and nMmbAge between 18 and 55)
           )
      AND cSttsDesc like 'No, Eligible' 
      AND DATE_FORMAT(dSrvyOn , '%m-%Y') < DATE_FORMAT('2012-08-01' , '%m-%Y' )
 GROUP BY cDistName , cTlkName, cGpName, cVlgName , 
        DATE_FORMAT(dSrvyOn , '%m-%Y')

私はフォーラムや外部で検索し、与えられたヒントのいくつかを使用しましたが、ほとんど違いはありません. 上記のクエリで使用した結合は、主キーと外部キーですべて結合したままです。このSQLを変更して実行時間を短縮する方法を教えてください....

4

7 に答える 7

2

あなたは非常に要求の厳しい MySQL ユーザーです。あなたが言及した速度で大規模に結合された結果セットから取得された100万レコードは、レコードあたり76マイクロ秒です。多くの人は、これが許容できるパフォーマンスであると考えています。クライアント ソフトウェアは、そのサイズの結果セットを制限する要因になる可能性があることに注意してください。クライアント ソフトウェアは、膨大な結果セットを消費し、それを処理する必要があります。

そうは言っても、いくつかの問題があります。

まず、クエリを書き直して、すべての列名がテーブル名で修飾されるようにします。これは、自分自身と、それを維持する次の人のために行います。WHERE基準が何をする必要があるかを一目で確認できます。

次に、この検索条件を検討してください。のため、2 回の検索が必要ORです。

 WHERE (
           (MEMBERS.nMmbGndrID = 1 and MEMBERS.nMmbAge between 18 and 60) 
       or  (MEMBERS.nMmbGndrID = 2 and MEMBERS.nMmbAge between 18 and 55)
       )

これらの基準は、18 歳から 60 歳の女性と 18 歳から 55 歳の男性 (推測) のほとんどの母集団に一致すると思います。LEFT JOIN のリストの最初に MEMBERS テーブルを配置できますか? または、テーブルに派生列 (MEMBERS.working_age = 1 など) を配置できますか?

また、MEMBERS の (nMmbGndrID,nMmbAge) の複合インデックスを試して、これを高速化します。機能する場合と機能しない場合があります。

第三に、この基準を検討してください。

  AND DATE_FORMAT(dSrvyOn , '%m-%Y') < DATE_FORMAT('2012-08-01' , '%m-%Y' )

関数を dSrvyOn 列に適用しました。これにより、その検索でのインデックスの使用が無効になります。代わりに、これを試してください。

  AND dSrvyOn >= '2102-08-01'
  AND dSrvyOn <  '2012-08-01' + INTERVAL 1 MONTH

これにより、dSrvyOn にインデックスがある場合、そのインデックスで範囲検索が実行されます。私の発言は、ORDER BY 句の関数にも当てはまります。

最後に、他の誰かが述べたように、LIKEどこで行うかを検索するために使用しないで=ください。column LIKE '%something%'また、許容できるパフォーマンスが必要な場合は、決して使用しないでください。

于 2012-11-21T13:48:32.600 に答える
1

あなたは、適切でユニークなインデックスに基づいて結合を行っていると主張しています。したがって、最適化する必要はほとんどありません。多分いくつかのヒント:

  • テーブルのレイアウトを最適化してみてください。必要な結合の数を減らすことができるかもしれません。これはおそらく、何よりもパフォーマンスの最適化をもたらします。

  • ハードウェア (利用可能なメモリなど) とサーバー構成を確認してください。

  • mysqlsexplain機能を使用してボトルネックを見つけます。

  • おそらく、バックグラウンド プロセスによって埋められる、このクエリ用に特別に補助テーブルを作成することができます。そうすれば、バックグラウンドでクエリの前に作業が行われるため、クエリ自体がより高速に実行されます。これは通常、クエリが、データベース内のすべての変更と必ずしも同期してはならないデータを取得する場合に機能します。

  • RDBMS が本当に適切なタイプのデータベースであるかどうかを確認します。多くの目的で、グラフ データベースははるかに効率的で、優れたパフォーマンスを提供します。

于 2012-11-21T13:34:11.793 に答える
0

オペレーターがあなたlikeを妨害している可能性があります -- を使用した全文検索likeは MySQL の長所ではありません。

フルテキスト インデックスをオンに設定することを検討してください(最初にフィールドcSttsDescであることを確認してください)。TEXT

ALTER TABLE articles ADD FULLTEXT(cSttsDesc);

SELECT
    *
FROM
    table_name
 WHERE MATCH(cSttsDesc) AGAINST('No, Eligible')

または、代わりにブール値フラグを設定できますcSttsDesc like 'No, Eligible'

ソース: http://devzone.zend.com/26/using-mysql-full-text-searching/

于 2012-11-21T13:40:20.847 に答える
0

nMmbGndrID、nMmbAge、および cSttsDesc にインデックスを追加して、それがクエリに役立つかどうかを確認してください。

さらに、select ステートメントの前に「Explain」コマンドを使用して、より良い方法についてのヒントを得ることができます。Explain の詳細については、MySQL リファレンスを参照してください。

于 2012-11-21T13:26:29.417 に答える
0

この SQL には、explain.

フィールドが必要な場合、それは LEFT JOIN にあるテーブルにあるべきではありません。

すべての必須フィールドが同じテーブルにある場合は、最初の FROM にある必要があります。

テキスト検索が (ユーザー入力からではなく) 予測可能であり、単一の既知の ID に関連している場合は、テキスト検索ではなく ID を使用します (LIKE ボトルネックを見つけた Patricia に感謝します)。

テーブル ヒントがないためクエリが読みにくいですが、フィールド名にはパターンがあるようです。

nMmbGndrIDandに値を指定する必要がありnMmbAgeますが、これらはおそらく MEMBERS にあり、左結合が 5 つ下にあります。それは冗長性です。

次のような単純な結合を実行できることを覚えておいてください。

FROM sspk.villages, gps, TALUKS, dists, HHINFO, MEMBERS [...] WHERE [...] nVlgGpID = nGpID AND nGpTlkID = nTlkID AND nTlkDistID = nDistID AND nHLstGpID = nGpID AND nHLstID = nMmbHhiID

cSttsDescから来ているようSTATUSです。ただし、テキスト'No, Eligible'が正確に 1 つの nBStsSttsID と一致する場合はBNFTSTTS、値を見つけて使用してください。7 の場合は、 を取り出してLEFT JOIN STATUS ON nBStsSttsID = nSttsIDに置き換えAND cSttsDesc like 'No, Eligible' ますAND nBStsSttsID = '7'。これにより、速度が大幅に向上します。

于 2012-11-21T13:31:10.813 に答える
0

結合で使用されるテーブルが更新クエリにほとんど使用されない場合は、おそらくエンジンの種類を INNODB から MyISAM に変更できます。

MyISAM の選択クエリは、INNODB よりも 2 倍速く実行されますが、MyISAM では更新と挿入クエリの速度が大幅に低下します。

于 2012-11-21T13:31:25.547 に答える
0

長いクエリと時間を回避するために、ビューを作成できます。

于 2012-11-21T13:31:55.640 に答える