2

このクエリを最初に作成したとき、テーブルが比較的小さかったときは非常に高速に実行されましたが、時間の経過とともに更新テーブルのサイズが大きくなり (現在は約 6000 行)、クエリは非常に遅くなり、リソースを大量に消費するようになりました。私が使用しているサーバーは、linode.com の 1GB RAM VPS であり、クエリが完了するまで実際には十分な時間待ちませんでした。

興味深いことに、左結合 (SELECT MAX(u2.time)) に余分な条件がなければ、0.5 秒未満で実行されます。

クエリの実行中に mySQL のプロセス リストを確認したところ、ずっと「データを送信中」と表示されていました。

クエリは次のとおりです。

SELECT 
  s.ID as sid, s.country AS country, 
  s.name AS name, s.ip AS ip, 
  u.connPlayers AS cp, u.maxPlayers AS mp
FROM servers AS s 

LEFT JOIN updates AS u 
  ON u.serverID = s.ID 
  AND u.time = 
      (SELECT MAX(u2.time) 
         FROM updates AS u2 
         WHERE u2.serverID = s.ID) 
ORDER BY RAND(MINUTE(NOW())) 
LIMIT 0,10

my.cnf ファイルは次のとおりです: http://redream.co.nz/my.cnf

テーブル構造:

サーバー テーブル (20 行)

Field   Type
ID      int(10) Unique Key           
ip      varchar(200)                 
country varchar(2)               
name    varchar(600)             
motd    varchar(600)                 
desc    mediumtext               
version varchar(600)    

テーブルの更新 (6000 行)

Field       Type
serverID    int(10)              
ping        int(10)              
time        int(14)              
uptime      int(10)              
connPlayers int(10)              
maxPlayers  int(10)              
uptime      int(14)
4

3 に答える 3

2

サブクエリは、andの外積とandの外積のSelect MAX(...各行に対して実行され、その後再び実行されます。MySQL のオプティマイザーはあまり洗練されていません。updatesserversserversupdatesupdates

更新: 私の SQL は少しさびていますが、次のようなことを試してみてください:

SELECT
  /* blah */
FROM
  servrs s
LEFT JOIN
  updates u
ON
  u.serverID = s.ID
GROUP BY s.serverID
HAVING MAX(u.time)

私は手元に MySQL インスタンスを持っていないので、これを機能させるにはおそらくこれを少し調整する必要があります。

Update2: コードを詳しく調べたところ、このクエリのコストは当初の見積もりよりも大きいと思います。この回答の上部を更新しました。

于 2012-06-11T01:00:19.087 に答える
0

私は MySQL の専門家ではありませんが、これは MySQL でうまくいくと思います。

SELECT 
  s.ID as sid, s.country AS country, 
  s.name AS name, s.ip AS ip, 
  u.connPlayers AS cp, u.maxPlayers AS mp
FROM servers AS s 

LEFT JOIN (
    SELECT u.serverId, u.connPlayers, u.maxPlayers
    FROM updates u
    INNER JOIN (SELECT serverId, max(time) AS 'maxTime' FROM updates GROUP BY serverId) AS u2
        ON u.serverId = u2.serverId AND u.time = u2.maxTime 
) AS u ON u.serverID = s.ID 

ORDER BY RAND(MINUTE(NOW())) 
LIMIT 0,10

重要な変更点は、左結合に次のサブクエリが含まれるようになったことです。

SELECT u.serverId, u.connPlayers, u.maxPlayers
FROM updates u
INNER JOIN (SELECT serverId, max(time) AS 'maxTime' FROM updates GROUP BY serverId) AS u2
    ON u.serverId = u2.serverId AND u.time = u2.maxTime 

このサブクエリにもサブクエリが含まれており、serverId ごとに最大時間値を含む行を返します。上記のサブクエリは、外積の各行ではなく、1 回だけ実行されます。

于 2012-06-11T01:38:32.143 に答える
0

あなたが説明したプラットフォームで実行されているMySQLでは、6000行はごくわずかです。

私が最初にチェックするのは、あなたの my.ini ファイルです。すぐに使用できるファイル (最新のサーバーでは十分に構成されていないファイル) のいずれかを使用していますか? その場合、最初の答えは、my.ini を編集して適切な量のメモリを MySQL に割り当てることです。

それについて助けが必要な場合は、my.ini ファイル (パスワードを除く) を投稿してください。この種のパフォーマンスの低下を引き起こす可能性のあるものがいくつかあるためです。

また、クエリがより高速に実行されていた場合 (行updates数がはるかに少なかった場合)、その時点の行数と比較して、クエリによって返される行数はどれくらいでしupdatesたか?

現在、何行ありserversますか?

于 2012-06-11T00:55:04.533 に答える