簡體   English   中英

為什么 time_bucket_gapfill 在第 10 個請求時始終拋出 PSQLException?

[英]Why does time_bucket_gapfill consistently throw a PSQLException, at 10th request?

我有一個 Spring Boot 應用程序,帶有一個 REST 服務,我在其中使用了 JdbcTemplate。 然后我有一個帶有 TimescaleDB(版本 2.3.0)的 PostgreSQL,用於存儲數據。

在我的一個端點中,我調用以下代碼從客戶端本地時區的數據庫中獲取一些時間戳:

SELECT time_bucket_gapfill(CAST(:numOfHours * INTERVAL '1 hour' AS INTERVAL), 
       timestamp AT TIME ZONE 'UTC' AT TIME ZONE :timezone,
       :start AT TIME ZONE :timezone, :end AT TIME ZONE :timezone) AS time
FROM info
WHERE timestamp >= :start AND timestamp < :end
GROUP BY time

當我調用該特定端點時,它在前 9 次完美返回數據,然后在第 10 次,它拋出以下 SQL 錯誤:

ERROR: invalid time_bucket_gapfill argument: start must be a simple expression

TimescaleDB 手冊指出:

請注意,顯式提供的startstop或派生自 WHERE 子句的值需要是簡單的表達式。 此類表達式應在查詢計划中計算為常量。 例如,簡單表達式可以包含常量或調用now() ,但不能引用表的列。

他們想說的是這些參數必須是常量。 所以你不能在這里使用參數。

為什么這適用於前 10 次執行是因為 JDBC 驅動程序和 PostgreSQL 處理這些參數的方式:

  • 對於 JDBC java.sql.PreparedStatement的前 5 次執行,PostgreSQL 驅動程序將參數插入到查詢中並發送一個簡單的查詢字符串

  • 從第六次執行開始,JDBC 驅動認為值得在 PostgreSQL 中創建一個命名的准備好的語句

  • 在准備好的語句的前五次執行期間,PostgreSQL 生成一個使用實際參數值的自定義計划

  • 只有從第六次執行開始,PostgreSQL 才會考慮通用計划,其中參數是占位符

執行此通用計划會導致 TimescaleDB 錯誤。

所以有幾種補救措施:

  1. 不要在那里使用參數。 這是最好和最可靠的解決方案。 但是,那么您就不能使用准備好的語句,而是必須每次都構造查詢字符串(動態 SQL)。

  2. 請參閱JDBC 驅動程序文檔

    使用PreparedStatement API 時,驅動程序默認使用服務器端准備好的語句。 為了進入服務器端准備,您需要執行 5 次查詢(可以通過prepareThreshold連接屬性進行配置)。 內部計數器會跟蹤語句已執行的次數,以及當它達到閾值時,它將開始使用服務器端准備好的語句。

    這允許您通過將prepareThreshold設置為 0 來解決該問題,但代價是性能較差。

  3. 將 PostgreSQL 參數plan_cache_mode設置為force_custom_plan以避免使用通用計划。 這可能會對您的整體表現產生負面影響。

所有三種解決方案都會降低准備好的語句的有效性,但這是解決 TimescaleDB 的這個限制所必須付出的代價。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM