[英]Is it normal for an EF SqlQuery query to be 20x slower than a direct query?
[英]Node is 20x faster Than .NET Core in Connecting to Postgres
我有兩台服務器連接到 Azure 上托管的PostgresSQL 9.6
數據庫。 服務器正在做一件事 - 每 5 秒用SELECT 1
查詢訪問 Postgres 數據庫。
連接到數據庫並獲取數據的典型時間:
25 MS
500 MS
我的問題是我的 .NET Core 應用程序在獲取數據方面比 Node慢 20 倍。 我相信.NET Core 由於某種原因沒有匯集連接。 這種緩慢發生在本地運行應用程序和在 Azure 應用程序服務上運行它時 - 沒有區別。 我想解決 .NET --> Postgres 緩慢的問題。
請只瀏覽相關細節,不要在這一點上閱讀整個內容 - 我相信只有.NET Core
代碼是相關的。
從我的機器( Node
和.NET Core
應用程序都在其上運行)到數據庫的PsPing
:
Connecting to foobarPostGres:5432 (warmup): from someIp: 19.98ms
Connecting to foobarPostGres:5432: from someIp: 1.65ms
Connecting to foobarPostGres:5432 from someIp: 1.18ms
Connecting to foobarPostGres:5432: from someIp: 1.23ms
Connecting to foobarPostGres:5432: from someIp: 1.06ms
為了完整起見,一個NODE
時間的示例如下所示(注意它第一次建立連接時,它也是“慢”的):
Attempting to establish a connection...
Elapsed ms: 644.1334999799728
RESP: { '?column?': 1 }
Elapsed ms: 22.76109904050827
RESP: { '?column?': 1 }
Elapsed ms: 21.984400033950806
RESP: { '?column?': 1 }
Elapsed ms: 26.043799996376038
RESP: { '?column?': 1 }
Elapsed ms: 22.538798987865448
RESP: { '?column?': 1 }
.NET Core
連接時間如下所示:
5:13:32 PM: SLOW QUERY, CONN TIME: 4153, QUERY TIME: 18
5:13:53 PM: SLOW QUERY, CONN TIME: 707, QUERY TIME: 17
5:14:14 PM: SLOW QUERY, CONN TIME: 589, QUERY TIME: 16
5:14:35 PM: SLOW QUERY, CONN TIME: 663, QUERY TIME: 18
5:14:56 PM: SLOW QUERY, CONN TIME: 705, QUERY TIME: 16
注意初始連接時間超慢,后續請求建立連接時間長。
無論如何,因為我很絕望,我現在要轉儲我所有的代碼,並附上解釋。 連接字符串如下所示:
public static string CONNECTION_STRING {
get {
return $"Server={HOST}; User Id={USER}; Database={DB_NAME}; Port={PORT}; Password={PWD}; SSLMode=Prefer";
}
}
我的理解是,如果我使用此連接字符串,我應該立即使用連接池。 請注意,我已嘗試在數據庫上打開SSL
並將該行取出 - 它沒有幫助。
我的健康檢查控制器如下所示:
// GET api/health/getdbhealthselectone
[HttpGet]
[Route("getdbhealthselectone")]
public async Task<IActionResult> GetDbHealthSelectOne()
{
int testData = await _healthCheckRepo.RunHealthCheckSelectOne();
return Ok(testData);
}
我的健康檢查回購方法如下所示:
public async Task<int> RunHealthCheckSelectOne()
{
await using var conn = new NpgsqlConnection(AzureDbConnectionInfo.CONNECTION_STRING);
var connTimer = System.Diagnostics.Stopwatch.StartNew(); // TODO: Remove this testing line
await conn.OpenAsync();
connTimer.Stop(); // TODO: Remove this testing line
var msToConnect = connTimer.ElapsedMilliseconds; // TODO: Remove this testing line
int testData = 999;
var jobsQueryTimer = System.Diagnostics.Stopwatch.StartNew(); // TODO: Remove this testing line0
await using (var cmd = new NpgsqlCommand("SELECT 1", conn))
await using (var reader = await cmd.ExecuteReaderAsync())
while (await reader.ReadAsync()) {
testData = reader.GetInt32(0);
};
jobsQueryTimer.Stop(); // TODO: Remove this testing line
var msToQuery = jobsQueryTimer.ElapsedMilliseconds; // TODO: Remove this testing line
LogQueryIfSlow(msToConnect, msToQuery, _logger); // TODO: Remove this testing line
return testData;
}
注意這里的計時器 - await conn.OpenAsync();
到目前為止,大部分時間是什么,查詢本身很快。 另外,為了節省時間 - 我之前沒有async
運行此代碼,沒有區別。
最后,如果存在依賴注入問題,存儲庫位於類庫中,API 項目引用它,並且:
services.AddSingleton<IHealthCheckRepository, HealthCheckRepository>();
這是它的看法。
我相信這是所有相關信息 - 我一直在使用 Azure 支持電話,他們沒有發現 db 配置問題。 .NET Core 應用程序是超輕量級的,所以它不會超載並且正在測試中,所以除了我的測試之外沒有流量。
額外:為了完整起見,這是我的整個節點應用程序,它訪問數據庫並發布性能(取出 conn 數據)。
const { Pool, Client } = require('pg');
const { performance } = require('perf_hooks');
const pool = new Pool({
user: 'SECRET',
host: 'SECRET',
database: 'SECRET',
password: 'SECRET',
port: 5432,
})
function runQuery(pool) {
var t0 = performance.now();
pool.query('SELECT 1', (err, res) => {
if (err) {
console.log('ERROR: ', err.stack)
} else {
console.log('RESP: ', res.rows[0])
}
var t1 = performance.now();
console.log('Elapsed ms: ', t1-t0);
//pool.end()
});
}
setInterval(() => {runQuery(pool)}, 5000);
編輯:對於后代,這是修復連接池超時后 .NET Core 中的時間 - 它比節點快,除了初始連接,這似乎需要一段時間,但我沒有檢查一些默認值:
CONN: 1710 QUERY: 18
CONN: 0 QUERY: 16
CONN: 0 QUERY: 16
CONN: 0 QUERY: 17
CONN: 0 QUERY: 16
CONN: 0 QUERY: 23
CONN: 0 QUERY: 16
CONN: 0 QUERY: 16
CONN: 0 QUERY: 23
CONN: 0 QUERY: 16
CONN: 0 QUERY: 16
您需要設置最小池大小。 這樣做可確保無論池使用情況如何,此數量的連接都對數據庫保持打開狀態。
默認情況下(至少對於NPGSQL ),最小大小為 0,因此如果連接有一段時間沒有使用,它將被關閉。
在您的測試中,您每 5 秒執行一次調用,這並不多,並且池可能會決定關閉未使用的連接。 根據文檔,它應該保持打開狀態 300 秒,而不僅僅是 15
第一個調用幾乎比其他調用長 5 秒。 對我來說,這看起來像是 IP 地址解析問題。 它首先選擇對給定服務器有缺陷的方法,然后在 5 秒后超時並選擇另一個有效的方法。 然后它會被緩存一段時間,這樣會繼續正常工作,直到緩存的條目過期。
要查看這是否是問題,請將數據庫主機的 IP 地址硬編碼到“主機”文件中,然后查看是否可以解決問題。 如果是這樣,那么根本原因就成為您的網絡工程師的問題。
在數據庫方面,您可以打開慢查詢日志記錄, log_min_duration_statement
或更好的auto_explain.log_min_duration
。 但如果我的理論是正確的,這將不會顯示任何內容。 數據庫不知道您嘗試查找其 IP 地址花了多長時間。
有可能第一次查詢需要將大量數據從磁盤帶到內存,隨后的執行發現共享緩沖區中已經存在的所有內容。 你可以通過運行知道這一點
EXPLAIN (ANALYZE, BUFFERS) <your query>
“讀取”和“命中”的數量將告訴您從磁盤讀取了多少,以及在 RAM 中命中了多少。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.