0

特定の x/y/z 座標 (ゲーム プラグイン、fyi 用) について記録されたイベントについて、MySQL テーブルにクエリを実行します。このクエリは、まったく同じ座標に新しいエントリを持つレコードを除外するために、右結合で記述されています。

ただし、これはパフォーマンス キルです。

たとえば、1 つのクエリで約 32,000 の結果が返されます (通常はこれほど多くはありませんが、根本的な問題に対処する必要があります)。適切な結合比較を行わないと、33373 行がセット (0.19 秒) になります。

正しい結合では、セットで 32955 行かかります (3 分 7.99 秒)

3分は長すぎる。

右側の結合を含むクエリの例を次に示します。

SELECT prism_actions.id, prism_actions.action_time, prism_actions.action_type, prism_actions.player, prism_actions.world, prism_actions.x, prism_actions.y, prism_actions.z, prism_actions.data, DATE_FORMAT(prism_actions.action_time, '%c/%e/%y') display_date, DATE_FORMAT(prism_actions.action_time, '%l:%i%p') display_time
FROM prism_actions
RIGHT JOIN (SELECT action_type, x, y, z, max(action_time) as action_time FROM prism_actions GROUP BY action_type, x, y, z) latest 
ON prism_actions.action_time = latest.action_time
AND prism_actions.x = latest.x
AND prism_actions.y = latest.y
AND prism_actions.z = latest.z
AND prism_actions.action_type = latest.action_type
WHERE world = 'world'
AND (prism_actions.action_type = 'creeper-explode' OR prism_actions.action_type = 'entity-explode' OR prism_actions.action_type = 'tnt-explode' OR prism_actions.action_type = 'block-burn')
AND LEFT(prism_actions.action_type,5) != 'prism'
AND (prism_actions.x BETWEEN 2412.0286793077976 AND 2612.0286793077976)
AND (prism_actions.y BETWEEN -25.5 AND 174.5)
AND (prism_actions.z BETWEEN -2650.697295131335 AND -2450.697295131335)
ORDER BY prism_actions.action_time ASC, x ASC, z ASC, y ASC, id ASC
LIMIT 0,1000000

なしで、右の結合を削除するだけです。

だから私の質問は:

  • これは、新しいエントリを持つレコードを除外するための最良の方法ですか?
  • もしそうなら、パフォーマンスを改善するために私にできることはありますか?

私がこのようなクエリを使用する理由は、ソフトウェアがタイムスタンプで並べ替えられた結果を必要とするためですが、常に各 x/y/z での最新のアクティビティのみを認識している必要があるためです。そうしないと競合が発生します。

テーブル構造:

CREATE TABLE IF NOT EXISTS `prism_actions` (
  `id` int(11) unsigned NOT NULL auto_increment,
  `action_time` datetime NOT NULL,
  `action_type` varchar(25) NOT NULL,
  `player` varchar(16) NOT NULL,
  `world` varchar(255) NOT NULL,
  `x` int(11) NOT NULL,
  `y` int(11) NOT NULL,
  `z` int(11) NOT NULL,
  `data` varchar(255) NOT NULL,
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1;

上記のクエリの非常に縮小された領域の結果を説明します。

+----+-------------+---------------+------+---------------+------+---------+------+------+----------------------------------------------+
| id | select_type | table         | type | possible_keys | key  | key_len | ref  | rows | Extra                                        |
+----+-------------+---------------+------+---------------+------+---------+------+------+----------------------------------------------+
|  1 | PRIMARY     | <derived2>    | ALL  | NULL          | NULL | NULL    | NULL | 1870 | Using where; Using temporary; Using filesort | 
|  1 | PRIMARY     | prism_actions | ALL  | NULL          | NULL | NULL    | NULL | 1970 | Using where                                  | 
|  2 | DERIVED     | prism_actions | ALL  | NULL          | NULL | NULL    | NULL | 1970 | Using temporary; Using filesort              | 
+----+-------------+---------------+------+---------------+------+---------+------+------+----------------------------------------------+
3 rows in set (0.04 sec)
4

1 に答える 1

0

私の推測では、次のほうが少しうまくいくと思います。正しい答えが得られると仮定しますが、パフォーマンスにはあまり役立ちません。関連するテーブルに SHOW CREATE TABLE ステートメントを提供することを検討し、このクエリに EXPLAIN の出力を投稿してください...

SELECT pa.id
     , pa.action_time
     , pa.action_type
     , pa.player
     , pa.world
     , pa.x
     , pa.y
     , pa.z
     , pa.data
     , DATE_FORMAT(pa.action_time, '%c/%e/%y') display_date
     , DATE_FORMAT(pa.action_time, '%l:%i%p') display_time
  FROM prism_actions pa 
  JOIN 
     ( SELECT action_type
            , x
            , y
            , z
            , MAX(action_time) max_action_time 
         FROM prism_actions 
        GROUP 
           BY action_type
            , x
            , y
            , z
     ) latest 
    ON latest.max_action_time = pa.action_time 
   AND pa.x = latest.x
   AND pa.y = latest.y
   AND pa.z = latest.z
   AND pa.action_type = latest.action_type
 WHERE world = 'world'
   AND pa.action_type IN('creeper-explode','entity-explode','tnt-explode','block-burn')
   AND pa.action_type NOT LIKE 'prism%'
   AND pa.x BETWEEN 2412.0286793077976 AND 2612.0286793077976
   AND pa.y BETWEEN -25.5 AND 174.5
   AND pa.z BETWEEN -2650.697295131335 AND -2450.697295131335
 ORDER 
    BY pa.action_time ASC
     , x ASC
     , z ASC
     , y ASC
     , id ASC
 LIMIT 0,1000000;
于 2013-01-12T18:35:27.337 に答える