PHP PDO возвращает противоречивые результаты для SELECT FOUND_ROWS()

У меня проблема с PHP/PDO и MySQL

Когда я запускаю запрос с SQL_CALC_FOUND_ROWS, а затем выбираю FOUND_ROWS(), в 80% случаев он возвращает 0, а в остальное время FOUND_ROWS является точным

Я сократил его до простого тестового цикла, но он отлично работает на моем сервере разработки, но в тестовом примере возникает проблема несогласованности.

Выполнение одних и тех же запросов из командной строки MySQL работает корректно даже в продакшене, так что это похоже на проблему с PHP/PDO.

PHP 5.5.28 — использование mysqlnd 5.0.11-dev Percona Server 5.6.25-73.1-log на CentOS 6.6 (Final)

Кто-нибудь может помочь, пожалуйста? Я перепробовал все, что мог придумать, и я рву на себе волосы

<?php
require_once "../consts.php";

$nolimit_query = "select SQL_CALC_FOUND_ROWS targetusers.u_id
  FROM 
    users targetusers 
    LEFT JOIN user_extra targetuserextra ON (targetuserextra.ue_userid = targetusers.u_id) 
    LEFT JOIN countries ON (c_id = targetusers.u_country) 
    LEFT JOIN cities ON (cities.ct_countryid = c_id and cities.ct_id = targetusers.u_city) 
    LEFT JOIN userimages ON (targetusers.u_primaryimage = userimages.ui_id and userimages.ui_userid = targetusers.u_id and userimages.ui_imagetype = 'P') 
  WHERE 
    (targetusers.u_deleted = 0) and 
    (targetusers.u_id NOT IN (19, 32, 115)) and 
    (targetusers.u_active = 1) and 
    (targetusers.u_confirmed=5) order by u_lastupdated DESC LIMIT 10, 10";

// already tried this soln suggested elsewhere -- defaults to off for my PHP anyway though
ini_set("mysql.trace_mode", 0);
ini_set("display_errors", 1);

// set up PDO connection
$dbh = new PDO(
    "mysql:host=" . Config::Get()->DB_SERVER . ";dbname=" . Config::Get()->DATABASE_NAME . ";charset=utf8", 
    Config::Get()->DB_USERNAME, 
    Config::Get()->DB_PASSWORD
);
$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$dbh->setAttribute(PDO::ATTR_PERSISTENT, false);

echo $dbh->getAttribute(PDO::ATTR_CLIENT_VERSION) . "<br>";
echo $dbh->getAttribute(PDO::ATTR_DRIVER_NAME) . "<br>";
echo $dbh->getAttribute(PDO::ATTR_SERVER_INFO) . "<br>";
echo $dbh->getAttribute(PDO::ATTR_SERVER_VERSION) . "<br><br>";

echo date("r") . "<br>";
for ($i=0; $i<5; $i++)
{
    // run query above
    $stmt = $dbh->prepare($nolimit_query);
    if ($stmt === FALSE)
    {
        die($stmt->errorInfo());
    }

    // get result set 
    if (($result = $stmt->execute()) === TRUE)
    {
        $a = $stmt->fetchAll(PDO::FETCH_ASSOC);
        $stmt->closeCursor();
        $stmt = NULL;

        // this query returns inconsistent results (80% of the time it returns 0!)
        $b = $dbh->query("SELECT FOUND_ROWS() as cnt")->fetch(PDO::FETCH_ASSOC);
        echo "FOUND ROWS = " . $b["cnt"] . "<br>";      
    }
}

Вывод этого скрипта ниже.

Обратите внимание, что только 2 из 5 циклов возвращают правильное значение для FOUND_ROWS, а остальные 3 возвращаются как 0.

mysqlnd 5.0.11-dev - 20120503 - $Id: 15d5c781cfcad91193dceae1d2cdd127674ddb3e $
mysql
Uptime: 1857223 Threads: 1 Questions: 4446069 Slow queries: 32 Opens: 465 Flush tables: 1 Open tables: 403 Queries per second avg: 2.393
5.6.25-73.1

Fri, 04 Sep 2015 12:01:10 +0100
FOUND ROWS = 0
FOUND ROWS = 0
FOUND ROWS = 59836
FOUND ROWS = 0
FOUND ROWS = 59836

person carpii    schedule 04.09.2015    source источник
comment
Просто небольшой момент: вы устанавливаете режим ошибки в Exception, но вы не запускаете код базы данных в блоке try/catch.   -  person RiggsFolly    schedule 04.09.2015
comment
Вы также preparing оператор внутри цикла, в котором нет необходимости.   -  person RiggsFolly    schedule 04.09.2015
comment
Вы все делаете правильно, так как использование try catch для базового отчета об ошибках — не более чем заблуждение   -  person Your Common Sense    schedule 04.09.2015
comment
@Riggs, да, это самый простой тест, который я мог придумать. В моей реальной кодовой базе у меня есть обработчики исключений и т. д. Аналогично для prepare(), в производстве я привязываю параметры, поэтому подготовка требуется, тогда как в этом коде я удалил все это, чтобы упростить его.   -  person carpii    schedule 04.09.2015
comment
Я не понимаю, почему он должен терпеть неудачу 3 из 5 раз, но вы запускаете FOUND_ROWS второй запрос вне теста if, который проверяет первый запрос, попробуйте переместить второй запрос внутрь первой проверки запроса, а также добавить еще, чтобы сообщить о любой ошибке могло случиться с первым запросом   -  person RiggsFolly    schedule 04.09.2015
comment
Наконец-то я добрался до сути (к моему большому облегчению). Кажется, расширение NewRelic Application Monitoring как-то мешает этому. Звучит безумно, но комментируя их расширение из php.ini, внезапно FOUND_ROWS снова работает, как ожидалось.   -  person carpii    schedule 04.09.2015


Ответы (1)


Проблема решена. Оказывается, демон NewRelic Application Monitoring Daemon или расширение мешали результатам FOUND_ROWS().

Это так плохо :(

Отключение расширения и FOUND_ROWS снова пуленепробиваемо

person carpii    schedule 04.09.2015
comment
newrelic ведет расследование. Если кто-то еще столкнется с этой проблемой, обходной путь — установить newrelic.transaction_tracer.explain_enabled = false - person carpii; 04.09.2015