0

I was just hoping someone could help me speed up 4 queries with a multi query.

GOAL: a single multi query to function as the single queries below.

Simple queries, i am checking one table to see if user is banned, then if not, i am getting row for the id and updating it's view count by 1. If user is banned, i do not want the last to queries to complete.

Thank you in advance for your help.

current performance is around 1200ms. (+1000ms avg for facebook graph api query).

NOTE: af_freefeed.pageid & af_ban.pageid are both indexed in database.

ALSO: I have been studying and referencing from http://www.php.net/manual/en/mysqli.multi-query.php i just can not see how to get this config into multi with the if()

$fconn = new mysqli($fdbhost, $fdbuser, $fdbpass, $fdbname) or die  ('Error connecting to mysqli');
// 12,000 rows for af_ban - bigint(255) : indexed
$q = sprintf('SELECT COUNT(pageid) AS numrowst FROM af_ban WHERE pageid = %s', $banpage);
$readtop = $fconn->query($q);
$rowtop = $readtop->fetch_assoc();

// 1.17 million rows for af_freefeed - bigint(255) : indexed
if($rowtop[numrowst] == 0){
$q = sprintf('SELECT COUNT(pageid) AS numrowsf FROM af_freefeed WHERE pageid = %s', $banpage);
$readf = $fconn->query($q);
$rowf = $readf->fetch_assoc();
// increment views
$read = $fconn->query("Update af_freefeed SET views = views + 1 WHERE pageid = ".$banpage."");
}
$q=$fconn->query("SELECT pagename,views,pageid FROM af_freefeed ORDER BY views DESC LIMIT 0, 20");
unset($q);
unset($rowf);
unset($rowtop);
mysqli_close($fconn);

actual request times.

  1. grah api: 1127.04610825ms.
  2. conncect: 1.20711326599ms.
  3. check banned: 0.405788421631ms.
  4. get row: 418.189229965ms.
  5. increment views: 472.24655151ms.
  6. get top20: 94.31447983ms.

Multi_query #1 How to stop the multi query if user is banned?


Possible Contender: 943.8181ms. if added : 933.1279ms. if banned

  1. 10ms difference if exit loop for banned. This leads me to believe the loop is completing all the queries before they are actually supposed to be executed, "next_result". Or i have an error in how i looped the functions.

  2. replaced exit; with $thread_id = $fconn->thread_id; $fconn->kill($thread_id); if banned 953.4719ms. no gain.


$banpage='234232874008';
$query  = "SELECT pagename,views,pageid FROM af_freefeed ORDER BY views DESC LIMIT 0, 2;";
$query .= "SELECT pageid AS isbanned FROM af_ban WHERE pageid = \"".$banpage."\";";
$query .= "SELECT pageid AS isadded FROM af_freefeed WHERE pageid = \"".$banpage."\";";
$query .= "Update af_freefeed SET views = views + 1 WHERE pageid = \"".$banpage."\"";
/* execute multi query */
if ($fconn->multi_query($query)) {
   if ($result = $fconn->store_result()) {
      while ($row = $result->fetch_row()) {
            print_r($row).'<br />';
      }
      $result->free();
   }
if ($fconn->more_results()) {
    while ($fconn->next_result()){ 
        if($thisresult = $fconn->store_result()){                   
            while (is_array($row = $thisresult->fetch_array())) {               
                if(isset($row['isbanned'])){
                    if($row['isbanned']===''.$banpage.''){
                $thread_id = $fconn->thread_id;
                $fconn->kill($thread_id);
                    // exit; 
                    }
                }
            }

        }
    }
}           
}

unset($query);
unset($result);
unset($thisresult);

Multi_query #2 "current for benchmark" How to remove duplicate fields in result set after next_result()?


2.667ms. / 1032.2499ms. but print_r is showing duplicate fields in $thisresults?

**Array
(
    [0] => 37
    [id] => 37
    [1] => 159616034235
    [pageid] => 159616034235
    [2] => 
    [userid] => 
    [3] => 30343
    [views] => 30343
    [4] => Walmart
    [pagename] => Walmart
)**

$query = "SELECT pageid AS isbanned FROM af_ban WHERE pageid = \"".$banpage."\";";
$query .= "SELECT pageid AS isadded FROM af_freefeed WHERE pageid = \"".$banpage."\";";
$query .= "SELECT * FROM af_freefeed ORDER BY views DESC LIMIT 0, 20";
//$query .= "Update af_freefeed SET views = views + 1 WHERE pageid = \"".$banpage."\"";
/* execute multi query */
echo '<pre>';
$i=0;
if ($fconn->multi_query($query)) {
   if ($result = $fconn->store_result()) {
        //$row = $result->fetch_assoc();    
      while ($row = $result->fetch_assoc()) {
        print_r($row).'<br />';
      }
      $result->free();
    }
if ($fconn->more_results()) {
    while ($fconn->next_result()){ 
        if($thisresult = $fconn->store_result()){       
             while ($row2 = $thisresult->fetch_array()) {
                if(isset($row2['isadded'])){
                    if($row2['isadded']===''.$banpage.''){
                        $addone = $fconn->query("Update af_freefeed SET views = views + 1 WHERE pageid = ".$banpage."");

                    }
                }   
                                print_r($row2); 
            }

        }
    }
}       

}
/* determine our thread id */
$thread_id = $fconn->thread_id;
/* Kill connection */
$fconn->kill($thread_id);
//

echo '</pre><hr/>';

4

5 回答 5

3

编辑:所以现在,结论:(下面的测试用例)

无法控制多语句查询的后续语句的执行。
因此,您不能multi_query()以您想要的方式使用。

全部执行,或不执行。


关于
Multi_query #2 "current for benchmark" 如何在 next_result() 之后删除结果集中的重复字段?

使用fetch_assoc()or fetch_array(MYSQLI_ASSOC)(两者几乎相同)代替fetch_array().


关于 multi_query():

我最近使用 MySQL C API 编写了一个程序,mysqli 也使用了该 API。
关于多语句查询支持文档状态

执行多语句字符串可以产生多个结果集或行数指示符。处理这些结果涉及到与单语句情况不同的方法:处理完第一个语句的结果后,需要检查是否存在更多结果,如果存在则依次处理。为了支持多结果处理,C API 包括 mysql_more_results() 和 mysql_next_result() 函数。只要有更多结果可用,这些函数就会在循环结束时使用。未能以这种方式处理结果可能会导致与服务器的连接断开。

(强调补充)

这导致了一个结论,即中止多语句查询不是预期的功能

此外,我没有找到任何资源来解释实际执行后续查询的时间。
调用next_result()并不一定意味着查询尚未执行。


编辑:测试用例

为了证明我之前的假设,我创建了一个测试用例:

<?php
$db = new mysqli('localhost', 'root', '', 'common');
$query = 'SELECT NOW() as time;';
$query .= 'SELECT NOW() as time;';
$query .= 'SELECT NOW() as time;';
$query .= 'SELECT NOW() as time;';

if($db->multi_query($query)) {
    // Current time
    echo "'multi_query()' executed at:\n\t\t"
        .date('Y-m-d H:i:s')."\n";

    // First result
    if($result = $db->store_result()) {
        $i = 1;

        $row = $result->fetch_assoc();
        echo "'NOW()' of result $i:\n\t\t".$row['time']."\n";
        $result->free();
        // Wait 5 seconds
        sleep(5);

        // Subsequent results
        while($db->more_results() && $db->next_result()) {
            $result = $db->store_result();
            $row = $result->fetch_assoc();
            $i++;
            echo "'NOW()' of result $i:\n\t\t".$row['time']."\n";
            // Wait 5 seconds
            sleep(5);
            $result->free();
        }
    }
}
$db->close();
?>

这导致:

'multi_query()' executed at:
        2013-05-10 10:18:47
'NOW()' of result 1:
        2013-05-10 10:18:47
'NOW()' of result 2:
        2013-05-10 10:18:47
'NOW()' of result 3:
        2013-05-10 10:18:47
'NOW()' of result 4:
        2013-05-10 10:18:47

鉴于此,很明显查询的所有四个语句都是在调用之后直接执行的multi_query()
如果它们仅在调用后执行,那么我在循环迭代之间添加的调用next_result()会导致 5 秒的延迟。sleep(5)

于 2013-05-10T06:43:20.530 回答
3

尝试用于index获取计数。比如说COUNT(pageid)。它将加快您的查询速度。

更新

您也可以尝试这个链接以获得进一步的解释

于 2013-05-06T06:46:08.660 回答
1

请在 mysql 中运行以下查询并检查您的查询运行时间:

CREATE INDEX pagidIndex ON af_ban (pageid(11));
CREATE INDEX pagidFeedIndex ON af_freefeed (pageid(11));
CREATE INDEX viewsIndex ON af_freefeed (views(11));
于 2013-05-09T05:18:36.680 回答
1

我正在检查一个表以查看用户是否被禁止,如果没有,我将获取 id 行并将其视图计数更新为 1。

以下查询可能会帮助您更新查看次数。我假设您已经知道 page_id。

UPDATE af_freefeed SET views=views+1 WHERE page_id=%s and page_id not in (select page_id from af_ban WHERE page_id=%s);

于 2013-05-09T06:30:47.917 回答
0

您可以尝试以下方法:

$sql = sprintf("SELECT af_freefeed.pageid FROM af_freefeed left join af_ban ".
               "on (af_freefeed.pageid = af_ban.pageid) ".
               "where af_freefeed.pageid = %s and ".
               "af_ban.pageid is null limit 1", $pageid);

替换您的前两个查询。

结果中存在记录应表明请求资源的未禁止用户。然后你可以更新你的观点。

希望这可以帮助。

于 2013-05-09T16:53:51.727 回答