1

I have the following query

$samecars = $this->QueryResult("SELECT * FROM carads where STATUS='1' and DEL='0' 
and TITLE !='' and IMAGE1 != '' and IMAGE1 != '-1' and PRICE BETWEEN $pricelow 
and $pricehigh order by RAND() LIMIT 0,3");

When I remove RAND() the query is executed almost instantly, if I add the RAND() it takes about 10-30 seconds.

There are about 1 million rows in the table carads. I need RAND() in order to use random displaying.

More details:

QueryResult looks like this

public function QueryResult($strQuery) {
    $this->connector();
    $query = mysqli_query($this->link, $strQuery);
    $arr = array();
    if ($query) {
        while ($result = mysqli_fetch_object($query)) {
            array_push($arr, $result);
        }
    }
    $this->close();
    return $arr;
}

ALSO I tried add in SQL the following example command

SELECT * FROM carads where STATUS='1' and DEL='0' 
and TITLE !='' and IMAGE1 != '' and IMAGE1 != '-1' and PRICE BETWEEN 8000 
and 15000 order by RAND() LIMIT 0,3"

and RAND() is highlighted red and when i execute it through #1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '"' at line 3

user3140607
  • 303
  • 4
  • 19

2 Answers2

3

1. Russian roulette sampling

The reason why RAND() causes problems is because all rows of the table are queried instead of for instance the first three. Furthermore sorting takes some time.

An idea to speed up processing is using Russian roulette sampling:

SELECT * FROM carads where STATUS='1' and DEL='0' and TITLE !='' and IMAGE1 != '' and IMAGE1 != '-1' and PRICE BETWEEN $pricelow and $pricehigh AND RAND() < 0.001 LIMIT 0,3

where 0.001 is fairly small. The problem with this method is that items will not be picked uniformly (first items have more chance). Furthermore the probability should depend on the size of the table (so occasionally, an administration tool should recalculate the probability). However it is a pragmatic solution to the problem.

2. PHP does (most) of the work

Since there are only three rows, you could execute the following procedure:

  1. First query the database to find the number of rows
  2. Generate three distinct random numbers between 0 and the number of rows (exclusive)
  3. Query the three rows and process the data.
Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
  • I added 0.01 and now it's processing it in 0.03 secs from 45 secs. and they are random, 10 refreshes and never encountered same car. – user3140607 Jan 20 '14 at 11:25
  • "10 refreshes and never encountered same car" - hardly a definitive test of uniformity! – Mitch Wheat Jan 20 '14 at 11:48
  • As I claim in the answer, the items are indeed not uniform: the first elements have more chance to be picked than the last ones. In engineering however, there is the law of "conservation of misery". Sometimes one needs to sacrifice some quality to make it feasible. – Willem Van Onsem Jan 20 '14 at 11:53
  • @CommuSoft: I was referring to user3140607: I'm aware of this technique: http://mitch-wheat.blogspot.com.au/2011/08/t-sql-generating-random-numbers-random.html – Mitch Wheat Jan 20 '14 at 11:59
0

Another reason why the query is executing slowly is that when using an aggregate function like rand(), time functions and etc... prevents the query to be cached. So a good practice is to try and not to use these kind of functions in the SQL query and pass it with php like:

$query = "SELECT * FROM table order by " . rand();

instead of

$query = "SELECT * FROM table order by RAND()";

Hope it was useful.

Regards

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
gprusiiski
  • 430
  • 4
  • 18
  • I don't see how this might work. The resulting query becomes for instance `SELECT * FROM table order by 0.75165156`. That means that all the rows have the same order-attribute. Therefore SQL will probably yield the original order (or at least a deterministic one). – Willem Van Onsem Jan 20 '14 at 18:07