簡體   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