简体   繁体   中英

optimize sql query inside foreach

I need help optimizing the below querys for a recurrent calendar i've built.

if user fail to accomplish all task where date

This is the query i use inside a forech which fetched all dates that the current activity is active.

This is my current setup, which works, but is very slow.

Other string explained:

$today=date("Y-m-d");
$parts = explode($sepparator, $datespan);
$dayForDate2 = date("l", mktime(0, 0, 0, $parts[1], $parts[2], $parts[0]));
$week2 = strtotime($datespan); 
$week2 = date("W", $week2);
if($week2&1) { $weektype2 = "3"; } # Odd week 1, 3, 5 ... 
else         { $weektype2 = "2"; } # Even week 2, 4, 6 ...

Query1:

$query1 = "SELECT date_from, date_to, bok_id, kommentar
              FROM bokningar
              WHERE bokningar.typ='2'
                and date_from<'".$today."'";

function that makes the foreach move ahead one day at the time...

function date_range($first, $last, $step = '+1 day', $output_format = 'Y-m-d' )
{

  $dates = array();
  $current = strtotime($first);
  $last = strtotime($last);

  while( $current <= $last ) {

    $dates[] = date($output_format, $current);
    $current = strtotime($step, $current);
  }

  return $dates;
}

foreach:

foreach (date_range($row['date_from'], $row['date_to'], "+1 day", "Y-m-d")
         as $datespan)
   if ($datespan < $today)

Query 2:

$query2 = "
    SELECT bok_id, kommentar
        FROM bokningar b
        WHERE b.typ='2'
          AND b.bok_id='".$row['bok_id']."'
          AND b.weektype = '1'
          AND b.".$dayForDate2." = '1'
          AND NOT EXISTS 
              (SELECT t.tilldelad, t.bok_id
                  FROM tilldelade t
                  WHERE t.tilldelad = '".$datespan."'
                    AND t.bok_id='".$row['bok_id']."')

           OR   b.typ='2'
          AND b.bok_id='".$row['bok_id']."'
          AND b.weektype = '".$weektype2."'
          AND b.".$dayForDate2." = '1'
          AND NOT EXISTS 
                   (SELECT t.tilldelad, t.bok_id
                       FROM tilldelade t
                       WHERE t.tilldelad = '".$datespan."'
                         AND t.bok_id='".$row['bok_id']."')";

b.weektype is either 1,2 or 3 (every week, every even week, every uneven week)

bokningar needs INDEX(typ, date_from)

Instead of computing $today, you can do

and date_from < CURDATE()

Are you running $query2 for each date? How many days is that? You may be able to build a table of dates, then JOIN it to bokningar to do all the SELECTs in a single SELECT .

When doing x AND y OR x AND z , first add parenthes to make it clear which comes first AND or OR: (x AND y) OR (x AND z) . Then use a simple rule in Boolean arithmetic to transform it into a more efficient expression: x AND (y OR z) (where the parens are necessary).

The usual pattern for EXISTS is EXISTS ( SELECT 1 FROM ... ) ; there is no need to list columns.

If I am reading it correctly, the only difference is in testing b.weektype . So the WHERE can be simply

WHERE b.weektype IN ('".$weektype2."', '1')
  AND ...

There is no need for OR, since it is effectively in IN() .

tilldelade needs INDEX(tilldelad, bok_id) , in either order. This should make the EXISTS(...) run faster.

Finally, bokningar needs INDEX(typ, bok_id, weektype) in any order.

That is a lot to change and test. See if you can get those things done. If it still does not run fast enough, start a new Question with the new code. Please include SHOW CREATE TABLE for both tables.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM