0

私は大きなテーブルを持っています(約10m行、現時点ではすべて偽のテストデータです)。

id user と action はどちらも一意ではありませんが、ユーザーがアクションを実行できるのは 1 回だけです。(つまり、id_user と id_action の組み合わせは 1 つだけになります。

x と y はどちらも 1 ~ 100 の INT になります

すべての列にインデックスを付けました。

CREATE TABLE IF NOT EXISTS `test` (
`id_user` int(11) NOT NULL,
`id_action` int(11) NOT NULL,
`x` int(11) NOT NULL,
`y` int(11) NOT NULL,
KEY `x` (`x`),
KEY `y` (`y`),
KEY `id_user` (`id_user`),
KEY `id_action` (`id_action`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

作ろうとしているゲーム用です。

私がやりたいことは、y によって指示される範囲内で、x のスコアが類似している他のユーザーをテーブルで検索することです。

たとえば、ユーザー 1 が x で 75 のスコアでアクション 1 を実行し、y で 10 の範囲を持っているとします。65 から 85 のスコアを獲得した他のすべてのユーザーを表示したいと考えています (範囲は y で設定された 10 であるため)。

これは私が持っているもので、ローカルのラップトップで実行したところです.. 300秒後にタイムアウトしました... :(

SELECT * FROM test
WHERE
id_user != 1 AND
x BETWEEN
((SELECT x from test WHERE id_action = 1 AND id_user = 1) - (100 - (SELECT y FROM test WHERE id_action = 1 And id_user = 1)))
AND
((SELECT x from test WHERE id_action = 1 AND id_user = 1) + (100 - (SELECT y FROM test WHERE id_action = 1 And id_user = 1)));

私が持っている10,000,000行(100,000人のテストユーザーによる100のアクション..すべて乱数)でのこの検索は失敗します。

テーブルをそれ自体に結合することを今調査するつもりですが、サブセレクトの方が効率的だと思いました。私はここに行くにつれて学んでいます...アドバイスをいただければ幸いです... :)

4

1 に答える 1

1

x の範囲を取得するためのクエリと、実際の検索を行うためのクエリの 2 つに分割する方がはるかに簡単です。

本当に1つのクエリだけでやりたい場合は、これを試すことができます

Select t0.* from test t0, test t1 where t1.id_user=1 AND t0.id_user !=1 
AND abs(t1.x-t0.x) <= t1.y 

このクエリは自己結合であり、クエリよりもはるかに優れたパフォーマンスを発揮すると確信しています。また、abs 関数を使用して x 範囲をフィルター処理します。ところで、y が範囲 (たとえば 10) であり、ターゲット x の範囲が t1.x - t0.y から t1.x + t0.y であると仮定します。クエリの「100 - (select y ....」で混乱しました。

于 2013-07-20T13:11:06.073 に答える