我有一個查詢,它使用從整數陣列(不使用引數)動態生成WHERE id IN (1,2,3,...)串列的(1,2,3,...)位置。現在我有一個特定的查詢,它用 26623 個 ID 大約需要 500 毫秒,但用 26624 個 ID 需要 50 秒(慢 100 倍)。
我在https://sqlite.org/limits.html 中找不到任何看起來相關的東西
SELECT params.name AS name, json_group_array(DISTINCT params.value) AS "values"
FROM view_requests AS req, search_params(search) AS params
JOIN flows ON flows.request_id = req.id
WHERE search NOT IN ('', '?')
AND flows.id IN (1,2,3) /* <=== here more than 26623 IDs make it super slow */
GROUP BY params.name
ORDER BY json_array_length("values") DESC, params.name ASC
在我嘗試隔離可重現之前(例如search_params是自定義虛擬表),有沒有人知道我可能會遇到什么限制?這不是 ID 本身的數量,因為不同的查詢使用相同的 ID 運行得很好。
SQLite 3.36.0 版通過具有只讀資料庫的 Better-sqlite3 (Node.js)。我使用的唯一編譯指示是journal_mode = WAL.
編譯(https://github.com/JoshuaWise/better-sqlite3/blob/master/docs/compilation.md#bundled-configuration):
SQLITE_DQS=0
SQLITE_LIKE_DOESNT_MATCH_BLOBS
SQLITE_THREADSAFE=2
SQLITE_USE_URI=0
SQLITE_DEFAULT_MEMSTATUS=0
SQLITE_OMIT_DEPRECATED
SQLITE_OMIT_GET_TABLE
SQLITE_OMIT_TCL_VARIABLE
SQLITE_OMIT_PROGRESS_CALLBACK
SQLITE_OMIT_SHARED_CACHE
SQLITE_TRACE_SIZE_LIMIT=32
SQLITE_DEFAULT_CACHE_SIZE=-16000
SQLITE_DEFAULT_FOREIGN_KEYS=1
SQLITE_DEFAULT_WAL_SYNCHRONOUS=1
SQLITE_ENABLE_MATH_FUNCTIONS
SQLITE_ENABLE_DESERIALIZE
SQLITE_ENABLE_COLUMN_METADATA
SQLITE_ENABLE_UPDATE_DELETE_LIMIT
SQLITE_ENABLE_STAT4
SQLITE_ENABLE_FTS3_PARENTHESIS
SQLITE_ENABLE_FTS3
SQLITE_ENABLE_FTS4
SQLITE_ENABLE_FTS5
SQLITE_ENABLE_JSON1
SQLITE_ENABLE_RTREE
SQLITE_ENABLE_GEOPOLY
SQLITE_INTROSPECTION_PRAGMAS
SQLITE_SOUNDEX
HAVE_STDINT_H=1
HAVE_INT8_T=1
HAVE_INT16_T=1
HAVE_INT32_T=1
HAVE_UINT8_T=1
HAVE_UINT16_T=1
HAVE_UINT32_T=1
uj5u.com熱心網友回復:
這是來自 SQLite 論壇的答案。本質上,這是查詢計劃程式如何處理IN文字以及我的虛擬表估計的成本的組合。這意味著我遇到了查詢規劃器做出不同決定的確切時刻。
SQLite NGQP 是一個基于成本的查詢計劃器。帶有文字值串列的 IN () 運算子被實作為一種臨時表;有時 SQLite 決定創建索引并進行查找,有時它決定使用該表作為查詢的最外層回圈。
EXPLAIN QUERY PLAN 應該以更簡潔的方式顯示這一點。
如果在除錯模式下編譯并啟用 WHERETRACE,.wheretrace 命令將顯示 SQLite NGQP 如何達到其計劃。基本輸入是虛擬表的 xBestIndex 方法的回傳值,尤其是“行數”和“估計成本”。提供準確的估計至關重要。成本應該反映相對于 SQLite 原生表的處理成本。
請注意,您可以通過將 IN 表命名為 CTE 和 CROSS JOIN 來強制執行快速運行的查詢計劃。
https://sqlite.org/forum/forumpost/a3d68ed8b40cf583?t=h
我使用的解決方法是json_each將整數陣列序列化為 JSON 字串。在我的特定用例中,這還有一些其他好處(例如,我可以系結單個引數并使用任意數量的 ID 重新使用查詢),所以我不介意這樣做:
SELECT params.name AS name, json_group_array(DISTINCT params.value) AS "values"
FROM view_requests AS req, search_params(search) AS params
JOIN flows ON flows.request_id = req.id
WHERE search NOT IN ('', '?')
-AND flows.id IN (1,2,3)
AND flows.id IN (SELECT value FROM json_each('[1,2,3]'))
GROUP BY params.name
ORDER BY json_array_length("values") DESC, params.name ASC
我也知道 Better-sqlite3 的通用虛擬表實作在易于使用(它非常簡單)和實作最大性能之間進行了權衡。
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/336556.html
