2

memcached でキャッシュされた低速のクエリがありますが、正常に動作しますが、memcached が停止したかのように mysql で低速のクエリが大量に発生し、Web サイトがダウンすることがあります。

スロー クエリのグラフ: http://i.imgur.com/ReyWe.png

この時点で、30 秒で約 100 件のスロー クエリが取得されました。それは何ですか?クエリ:

# Query_time: 5.942602  Lock_time: 0.010214 Rows_sent: 10000  Rows_examined: 493139  

SET timestamp=1335194149;  
SELECT story_id FROM dug_stories d WHERE d.story_is_permanent=0  AND  
                       (  
                        (d.story_time>1335190543 AND (d.story_pluses-d.story_minuses) > 5)  
                        OR  
                        ( ( (d.story_pluses-d.story_minuses) > 12 OR (d.story_pluses >= 10 AND d.story_minuses<=0) )  AND d.story_cat!=48 AND d.st  
ory_cat!=131 AND d.story_cat!=55 AND d.story_cat!=44 AND d.story_cat!=126 AND d.story_cat!=53 AND d.story_cat!=370 AND d.story_cat!=381 AND d.stor  
y_cat!=304 AND d.story_cat!=497)  OR (d.story_cat=48 AND (d.story_pluses-d.story_minuses) > 9) OR (d.story_cat=131 AND (d.story_pluses-d.story_min  
uses) > 8) OR (d.story_cat=55 AND (d.story_pluses-d.story_minuses) > 8) OR (d.story_cat=44 AND (d.story_pluses-d.story_minuses) > 9) OR (d.story_c  
at=126 AND (d.story_pluses-d.story_minuses) > 13) OR (d.story_cat=53 AND (d.story_pluses-d.story_minuses) > 8) OR (d.story_cat=370 AND (d.story_pl  
uses-d.story_minuses) > 8) OR (d.story_cat=381 AND (d.story_pluses-d.story_minuses) > 8) OR (d.story_cat=304 AND (d.story_pluses-d.story_minuses)  
> 8) OR (d.story_cat=497 AND (d.story_pluses-d.story_minuses) > 9)  
                       )  
                       ORDER BY d.story_rating DESC, d.story_time DESC LIMIT 0, 10000;  



少し調整されたクエリ (すべての != カテゴリの代わりに、NOT カテゴリ IN (除外するカテゴリのリスト) に変更しましたが、読みやすくするために書式設定されています... また、SET TIMESTAMP 変数はクエリで使用されていませんでした) ...ハードコードされた値でした。

SET timestamp=1335194149;  
SELECT 
      story_id 
   FROM 
      dug_stories d 
   WHERE 
          d.story_is_permanent = 0  
      AND (     ( d.story_time > 1335190543 AND d.story_pluses - d.story_minuses > 5 )  
             OR (    (    d.story_pluses - d.story_minuses > 12 
                       OR (   d.story_pluses >= 10 AND d.story_minuses <= 0 ) 
                     )  
                  AND NOT d.story_cat IN ( 44, 48, 53, 55, 126, 131, 304, 370, 381, 497 )
                )
             OR ( d.story_cat = 44  AND d.story_pluses - d.story_minuses > 9 ) 
             OR ( d.story_cat = 48  AND d.story_pluses - d.story_minuses > 9 ) 
             OR ( d.story_cat = 53  AND d.story_pluses - d.story_minuses > 8 ) 
             OR ( d.story_cat = 55  AND d.story_pluses - d.story_minuses > 8 ) 
             OR ( d.story_cat = 126 AND d.story_pluses - d.story_minuses > 13 ) 
             OR ( d.story_cat = 131 AND d.story_pluses - d.story_minuses > 8 ) 
             OR ( d.story_cat = 304 AND d.story_pluses - d.story_minuses > 8 ) 
             OR ( d.story_cat = 370 AND d.story_pluses - d.story_minuses > 8 ) 
             OR ( d.story_cat = 381 AND d.story_pluses - d.story_minuses > 8 ) 
             OR ( d.story_cat = 497 AND d.story_pluses - d.story_minuses > 9 )  
          )  
   ORDER BY 
      d.story_rating DESC, 
      d.story_time DESC 
   LIMIT 
      0, 10000;  

助けてくれてどうもありがとう!そして私の下手な英語でごめんなさい:)

4

2 に答える 2

0

遅いログは、rows_examined が結果セットよりも大きい場合、インデックスが十分に活用されていないことを示している可能性があります。

理想的には、MySQL は WHERE 句のすべてのフィルター式に対して単一のインデックスを利用できる必要があります。AND と OR がすべてネストされており、複数の列を参照しているため、WHERE 句は非常に複雑です。MySQL は、インデックスを持っていても、おそらくこのクエリを最適化するためにインデックスを利用することはできません。

一般に、このタイプのクエリは、それぞれがインデックスを利用できるいくつかの小さなクエリに分割し、 を使用して結果を単一のクエリに結合することで改善できますUNION

たとえば、first_name にインデックスがあり、last_name にインデックスがある場合、次のクエリは次のようになります。

SELECT *
FROM Users
WHERE active = true
  AND ((first_name = 'Marcus') OR (last_name = 'Adams'))

次のように改善できます。

SELECT *
FROM Users
WHERE active = true
  AND first_name = 'Marcus'
UNION
SELECT *
FROM Users
WHERE active = true
  AND last_name = 'Adams'

LIMIT 句で 10000 よりも多くの行が検査されているという事実は、ORDER BY 句がファイルの並べ替えを利用している可能性があることも示しています。これにより、レコードの一部のみが必要な場合でも、MySQL がすべての作業を実行します。ほとんどの場合、すべての基準を処理するカバリング インデックスを利用する必要がありますが、これは不可能かもしれません。そうでない場合は、ORDER BY 句を削除するか、ご指摘のとおり、キャッシングに頼って時間を節約する必要があります。

ビジー状態のサーバーではクエリが遅くなる可能性があるため、負荷の高いサーバーではクエリ時間はパフォーマンスの測定値としては不十分です。と を使用EXPLAINSHOW PROFILEてクエリをプロファイリングし、サーバーに過度の負荷がかからないように改善する必要があります。

サーバー上で実行できるスレッドが多すぎると、カスケード効果が発生し、サーバーが停止する可能性があります。InnoDB を使用している場合は、スレッドの並行性が高すぎないことを確認してください。一度に 100 個または無制限のスレッドを (非常にゆっくりと) 提供しようとするよりも、全員を待たせて一度に 8 つのスレッドを (非常に迅速に) 提供する方がよいでしょう。

于 2012-04-24T14:03:20.340 に答える
0

読みやすくするためにクエリを調整する以外に、クエリをもう少し再構築してみます。
( Story_Is_Permanent, Story_Cat, Story_Time ) にインデックスがあることを確認します。

ユーザーに提示するための文字通りの説明を含む「ストーリーカテゴリ」テーブルがあると思います。とにかくすべてのカテゴリをクエリしているので、INCLUDE または EXCLUDE する特定のカテゴリにのみ基づいているため、INCLUDE の場合は、カテゴリの PLUSES と MINUSES の正味カウントにのみ基づいています。そのカテゴリテーブルの列に追加します...次のようなものです

DefaultToInclude   integer as 1 or 0
PlusMinusNetCount  integer

次に、カテゴリ テーブルに結合し、次のようにクエリを簡素化します。

SELECT 
      story_id 
   FROM 
      dug_stories d
         JOIN YourCategories YC
            on d.story_cat = YC.categoryID
   WHERE 
          d.story_is_permanent = 0  
      AND (     ( d.story_time > 1335190543 AND d.story_pluses - d.story_minuses > 5 )  
             OR (     YC.DefaultToInclude = 0 
                  AND (    d.story_pluses - d.story_minuses > 12 
                       OR (d.story_pluses >= 10 AND d.story_minuses <= 0 ) 
                      )  
                )
             OR (     YC.DefaultToInclude = 1 
                  AND d.story_pluses-d.story_minuses > YC.PlusMinusNetCount )
          )
 ORDER BY 
      d.story_rating DESC, 
      d.story_time DESC 
   LIMIT 
      0, 10000;  




(     YC.DefaultToInclude = 0 
  AND (    d.story_pluses - d.story_minuses > 12 
        OR (d.story_pluses >= 10 AND d.story_minuses <= 0 ) 
      )  
)

最終的には

OR (    (    d.story_pluses - d.story_minuses > 12 
          OR (   d.story_pluses >= 10 AND d.story_minuses <= 0 ) 
        )  
    AND d.story_cat!=48 
    AND d.story_cat!=131 
    AND d.story_cat!=55 
    AND d.story_cat!=44 
    AND d.story_cat!=126 
    AND d.story_cat!=53 
    AND d.story_cat!=370 
    AND d.story_cat!=381 
    AND d.story_cat!=304 
    AND d.story_cat!=497 
   )

 OR (     YC.DefaultToInclude = 1 
      AND d.story_pluses-d.story_minuses > YC.PlusMinusNetCount )

その後、最終的には

( OR ( d.story_cat = 44  AND d.story_pluses - d.story_minuses > 9 ) 
  OR ( d.story_cat = 48  AND d.story_pluses - d.story_minuses > 9 ) 
  OR ( d.story_cat = 53  AND d.story_pluses - d.story_minuses > 8 ) 
  OR ( d.story_cat = 55  AND d.story_pluses - d.story_minuses > 8 ) 
  OR ( d.story_cat = 126 AND d.story_pluses - d.story_minuses > 13 ) 
  OR ( d.story_cat = 131 AND d.story_pluses - d.story_minuses > 8 ) 
  OR ( d.story_cat = 304 AND d.story_pluses - d.story_minuses > 8 ) 
  OR ( d.story_cat = 370 AND d.story_pluses - d.story_minuses > 8 ) 
  OR ( d.story_cat = 381 AND d.story_pluses - d.story_minuses > 8 ) 
  OR ( d.story_cat = 497 AND d.story_pluses - d.story_minuses > 9 ) 
) 

これにより、すでに長いクエリにさらに OR / AND 条件を追加する必要なく、それぞれの「正味」カウントを持つ別のカテゴリを簡単に含める/除外する柔軟性が得られます。何があっても、ある条件のすべてのカテゴリと別の条件の他のすべてのカテゴリを調べているため、常に「dug_Stories」テーブル全体を調べる必要があるようです。タイムスタンプは NOT EQUAL カテゴリ専用ですが、他の条件にはタイムスタンプの制限はありません (提示されたクエリの間違いでない限り)。

于 2012-04-24T15:03:38.577 に答える