Tell me more ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

I've got a large table (10m rows approx, all fake test data at the moment.).

id user and action are both not unique, but a user can perform an action only once. (Meaning there will only ever be one combo of id_user and id_action.

x and y are both only going to be an INT of 1 - 100

I've indexed every column.

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

It's for a game I'm trying to build.

What I want to do is search the table for any other users that have similar scores of x, within a range dictated by y.

For example, if user 1 does action 1 with a score of 75 in x and has a range of 10 in y. I want to show all other users who scored from 65-85 (as the range is 10 set in y).

This is what I've got and I just ran it on my local laptop.. it timed out after 300 seconds... :(

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)));

This search on the 10,000,000 rows I have (100 actions with 100,000 test users.. all random numbers) just fails.

I'm going to investigate joining the table on to itself now, but I thought a sub-select would be more efficient. I'm learning as I go here... any advice would be appreciated... :)

share|improve this question

1 Answer

It is much easier to split it into 2 queries, one to get the range for x and the other to do the actual retrieval.

If you really want to do it in only one query, you can try this

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 

This query is a self join and I am pretty sure it performs much better than your query. I also use the abs function to filter the x range. By the way I assume the y is the range (e.g. 10) and the targeting x range is from t1.x - t0.y to t1.x + t0.y. I was confused by the "100 - (select y ...." in your query.

share|improve this answer
Now that I think about it, I'm confused by te 100 - too! I'm running your idea now... god way of thinking about it... – Beertastic 7 mins ago

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.