繁体   English   中英

使用远程数据库时简单Eloquent查询太慢

[英]Simple Eloquent query too slow when using remote database

问题编辑

服务器

32 GB RAM
innodb_buffer_pool_size=1400M

数据库

新鲜空桌:

fields(id, name, type, optional)

SHOW TABLE STATUS LIKE "fields" 结果

Name:fields|Engine:InnoDB|Row_format:Dynamic|Rows:0|Av_row_length:0|Data_length:16384|Max_data_length:0|Data_free:0|Auto_increment:null|Create_time:2022-08-01 12:52:42|Update_time:NULL|Check_time:NULL|Collation:utf8_general_ci|Checksum:NULL|Create_options:|Comment:|Max_index_length:0|Temporary:N

测试代码

Route::get('/', function () {
    $gtc = microtime(true);
    DB::connection()->getPdo();
    $total = round((microtime(true) - $gtc) * 1000);
    echo "Laravel Connection time: $total ms<br>";

    $gtc = microtime(true);
    DB::select('SELECT * FROM fields');
    $total = round((microtime(true) - $gtc) * 1000);
    echo "Laravel Get rows time: $total ms<br>";

    $gtc = microtime(true);
    DB::select('SELECT 1');
    $total = round((microtime(true) - $gtc) * 1000);
    echo "Laravel SELECT time: $total ms<br>";

    $gtc = microtime(true);
    $pdo = new MySQLModel(env('DB_HOST'), env('DB_DATABASE'), env('DB_USERNAME'), env('DB_PASSWORD'));
    $connection = $pdo->getConnection();
    $total = round((microtime(true) - $gtc) * 1000);
    echo "PDO Connection time: $total ms<br>";

    $gtc = microtime(true);
    $ps = $connection->prepare('SELECT* FROM fields');
    $ps->execute();
    $total = round((microtime(true) - $gtc) * 1000);
    echo "PDO Get rows time: $total ms<br>";

    $gtc = microtime(true);
    $ps = $connection->prepare('SELECT 1');
    $ps->execute();
    $total = round((microtime(true) - $gtc) * 1000);
    echo "PDO SELECT time: $total ms<br>";

    for($i = 0; $i<5; $i++) {
        print_r(DB::select('SELECT NOW(3)'));
        echo '<hr>';
    }
});

结果

Laravel Connection time: 549 ms
Laravel Get rows time: 136 ms
Laravel SELECT time: 137 ms
PDO Connection time: 282 ms
PDO Get rows time: 68 ms
PDO SELECT time: 68 ms
Array ( [0] => stdClass Object ( [NOW(3)] => 2022-08-01 13:24:10.784 ) ) 
Array ( [0] => stdClass Object ( [NOW(3)] => 2022-08-01 13:24:10.921 ) ) 
Array ( [0] => stdClass Object ( [NOW(3)] => 2022-08-01 13:24:11.057 ) ) 
Array ( [0] => stdClass Object ( [NOW(3)] => 2022-08-01 13:24:11.193 ) ) 
Array ( [0] => stdClass Object ( [NOW(3)] => 2022-08-01 13:24:11.333 ) ) 

如果数据库位于同一台服务器但与远程服务器连接时,则不会发生这种情况。

这一切都表明这是一个与 Eloquent 相关的连接问题,我还没有找到任何有关配置某些东西以防止查询执行量如此巨大增加的信息(在我所做的所有测试中往往会加倍)。

时间不一致:

不要打开秒表。 因为从disl取数据,第一次取比较慢; rest 运行速度更快。 由于缓存。

调音:

innodb_buffer_pool_size的值是多少? 服务器有多少内存?

连接:

该程序应该只连接一次,并在开始任何计时测试之前完成。 单独计时连接。 (是的,400 毫秒的连接是荒谬的。)

数据长度:

16K 是非空表的“最小”大小。 那是1块。 即使在最不强大的本地机器上, SELECT * FROM t也应该在 10ms 以下。

下一步:

如果您可以通过这种方式检测 Eloquent,我们可以专注于连接,而不会被 SELECT 分心:

在建立连接之前打印刚刚和之后的时间。

如果这不切实际,则将查询更改为简单的SELECT 1

另一种方法是循环执行并显示SELECT NOW(3) 5 次。 这应该证明 Eloquent 是否正在重新连接!

这是 Laravel 默认配置错误,它将多次查询服务器以设置 * * 数据库,而不是创建单个 SQL 查询以发送到 MySQL。

在 config/database.php 中将字符集设置为 null

'charset' => null,

它将阻止 Laravel 发送

"set names '{$config['charset']}'".$this->getCollation($config)

向服务器查询。

接下来在 mysql 密钥中的 config/app.php 中将严格设置为 NULL

'strict' => null,

它将防止 Laravel

$connection->prepare($this->strictMode($connection, $config))->execute();

或者

$connection->prepare("set session sql_mode='NO_ENGINE_SUBSTITUTION'")->execute();

这将防止服务器通信延迟,从而导致对服务器的连接请求更快。

Laravel Connection time: 268 ms

对于需要双倍时间的 SELECT 查询,到期

$statement = $this->prepared(
                $this->getPdoForSelect($useReadPdo)->prepare($query)
            );//+68 ms more!

它与 PDO 准备的服务器通信。

$statement->execute();//+68 ms more!

在 mysql 数组集中的选项键中设置PDO::ATTR_EMULATE_PREPARES => true以启用模拟准备并提高性能。

现在的性能应该和PDO差不多。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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