2

I have to run a query that has a limit and offset and I also need the total number of results to build pagination. It's a complex query with a lot of conditions and joins so I would like to avoid doing the query twice just to get a count.

According to mysql docs I can do this:

mysql> SELECT SQL_CALC_FOUND_ROWS * FROM tbl_name
    -> WHERE id > 100 LIMIT 10;
mysql> SELECT FOUND_ROWS();

But what happens when i'm getting thousands of requests at a time, eventually there will be an instance where this happens:

mysql> SELECT SQL_CALC_FOUND_ROWS * FROM tbl_name
    -> WHERE __CONDITION1__ > 100 LIMIT 10; //count from query 1
mysql> SELECT SQL_CALC_FOUND_ROWS * FROM tbl_name
    -> WHERE __CONDITION2__ LIMIT 10; //count from query 2
mysql> SELECT FOUND_ROWS(); //should be count form query 1 but it's count from query 2
mysql> SELECT FOUND_ROWS(); // count from query 2 but it's always 1

I've encapsulated the queries in separate transactions, but as far as I understand there's no guarantee it'll prevent this race condition.

So there's two questions, can i somehow force my transaction to prevent this race condition? If not, is there another way of doing it without doing the query again and retrieving a count?

caiocpricci2
  • 7,714
  • 10
  • 56
  • 88

1 Answers1

3

There are certain problems when it comes to transactions and different isolation levels prevent more or less of them. I've described this in my answer here.
A problem like the phantom read for example, can affect the result of a select like you're doing it, yes. But the result of SQL_CALC_FOUND_ROWS is stored as soon as the query finishes and is lost as soon as you execute another query in the same session. That is the important part. SQL_CALC_FOUND_ROWS is session bound. There is no way, that the result of another query in another session is stored in your current session. The use of SQL_CALC_FOUND_ROWS is not subject to race conditions. The result of the SELECT query, yes, but not the result of FOUND_ROWS(). Don't confuse this.

fancyPants
  • 50,732
  • 33
  • 89
  • 96