使用 System.Data.SQLite (C#) 的 SQLite 查询比在 SQLiteStudio 中要慢得多
Posted
技术标签:
【中文标题】使用 System.Data.SQLite (C#) 的 SQLite 查询比在 SQLiteStudio 中要慢得多【英文标题】:SQLite query dramatically slower with System.Data.SQLite (C#) than in SQLiteStudio 【发布时间】:2019-03-17 21:04:20 【问题描述】:我有一个在同一张表上运行多个联接的查询。它加入了SessionID
,这是一个不代表表中列的键,而是通过子字符串操作生成为new column
(另请参见下面的查询代码)。
因此,我无法主动在 SessionID 上创建索引,因为相关表 Logs
中不存在该列。
但是,当我在 SQLiteStudio (v3.1.1) 中运行查询时,查询运行得非常快。当我在 SQLiteStudio 中运行解释查询计划时,我确实看到了以下输出:
1 0 0 SEARCH TABLE logs USING INDEX i_Logs (Code=?)
2 0 0 SEARCH TABLE logs USING INDEX i_Logs (Code=?)
0 0 0 SEARCH TABLE logs USING INDEX i_Logs (Code=?)
0 1 1 SEARCH SUBQUERY 1 AS b USING AUTOMATIC COVERING INDEX (SessionID=?)
0 2 2 SEARCH SUBQUERY 2 AS c USING AUTOMATIC COVERING INDEX (SessionID=?)
我们可以看到,SQLite 使用了一个自动覆盖索引 SessionID。
当通过 System.Data.SQLite 从我的 C# 对同一个数据库运行相同的查询时,查询速度显着变慢(大约 50 次)。
当我在 C# 中运行解释查询计划时,我确实看到了以下输出:
7 0 0 SEARCH TABLE logs USING INDEX i_Logs (Code=?)
14 0 0 SEARCH TABLE logs USING INDEX i_Logs (Code=?)
48 0 0 SEARCH TABLE logs USING INDEX i_Logs (Code=?)
请注意,没有使用自动覆盖索引。
我尝试使用分析并为 SQLite 连接显式设置 automatic_index=true,但它不影响查询计划。
SQLite 查询是:
select a.username, a.PSMID, a.PSMHost, a.AccountName, A.TargetHost, a.TargetUser,
Case When info2 Not like '%DataBase=%' Then '' Else substr(info2, instr(info2, 'DataBase=') +9, (instr(info2, ';Dst') +- instr(info2, 'DataBase=') - 9)) End as TargetDataBase, a.ConnectionComponent, a.StartTime,
Case when c.time is not null then c.time else b.EndTime end as EndTime,
Case when c.SessionDuration is not null then c.SessionDuration else b.SessionDuration end as SessionDuration,
Case When c.RequestReason not like '%PSMSR169E%' and c.RequestReason != '' then 'Yes' else 'No' End as ErrorOccurred,
Case When c.RequestReason like '%PSMSR169E%' Then 'Yes' Else 'No' End as DurationElapsed, c.RequestReason As Message
from (SELECT info2, time as StartTime, username, replace(info1,'Root\','') as AccountName,
Case When info2 not like '%;DataBase=%' Then substr(info2, instr(info2, 'ApplicationType=') +16 , instr(info2, ';Dst') -17) Else substr(info2, instr(info2, 'ApplicationType=') +16 , instr(info2, ';DataBase=') -17)
End as ConnectionComponent, substr(info2, instr(info2, 'DstHost=') +8, (instr(info2, ';Pro') +- instr(info2, 'DstHost=') - 8)) as TargetHost, substr(info2, instr(info2, 'User=') +5, length(info2) - instr(info2, 'User=') -5) as TargetUser,
substr(info2, instr(info2, 'PSMID=') +6, (instr(info2, ';Session') - instr(info2, 'PSMID=') - 6)) as PSMID,
substr(info2, instr(info2, 'SessionID=') +10, (instr(info2, ';Src') - instr(info2, 'SessionID=') -10)) as SessionID,
substr(info2, instr(info2, 'SrcHost=') +8, (instr(info2, ';User') - instr(info2, 'SrcHost=') -8)) as PSMHost,
Null as SessionDuration from logs
where code in (300) and info2 != 0) a left join (select time as EndTime,
substr(info2, instr(info2, 'SessionDuration=') +16, (instr(info2, ';SessionID') - instr(info2, 'SessionDuration=') - 16)) as SessionDuration,
substr(info2, instr(info2, 'SessionID=') +10, (instr(info2, ';Src') - instr(info2, 'SessionID=') -10)) as SessionID
from logs
where code in (302) and info2 != 0) b on a.SessionID = b.SessionID left join (Select 'Yes' as PSMDisconnectFailed, time,
substr(info2, instr(info2, 'SessionID=') +10, (instr(info2, ';Src') - instr(info2, 'SessionID=') -10)) as SessionID,
substr(info2, instr(info2, 'SessionDuration=') +16, (instr(info2, ';SessionID') - instr(info2, 'SessionDuration=') - 16)) as SessionDuration, RequestReason
from logs where code in (303) and info2 != 0) c on a.SessionID = C.SessionID
有人知道如何进一步解决/调查此问题吗?
编辑#1:我正在使用以下命令在我的 C# 代码中建立连接:
public static SQLiteConnection connectToDB()
dbConnection = new SQLiteConnection("Data Source = data\\LOGS.db; Version = 3;");
dbConnection.Open();
return dbConnection;
编辑 #2:升级 SQLite Studio(现在使用 SQLite 版本 3.24.0)后,我看到与 System.Data.SQLite SQLit v3.27.0 版本相同的解释查询计划输出。 注意:“AUTOMATIC COVERING INDEX”部分现在也不见了。
7 0 0 SEARCH TABLE logs USING INDEX i_Logs (Code=?)
14 0 0 SEARCH TABLE logs USING INDEX i_Logs (Code=?)
48 0 0 SEARCH TABLE logs USING INDEX i_Logs (Code=?)
【问题讨论】:
这两个程序使用的是什么版本的 sqlite(它们可能不一样,尽管基于 EQP 输出都是旧的)。 你能重新格式化你的帖子,让 select 是可读的,而不是一个巨大的长行吗? 嗨@Shawn。运行命令“select sqlite_version();”时- 我看到以下输出: SQLiteStudio:3.15.0 C# 代码:3.27.2 我正在使用 System.Data.SQLite 1.0.110 和 SQLite Studio v3.1.1。 嗨@Shawn。我更新了 SQLite Studio,现在在运行“select sqlite_version();”时看到以下输出:3.24.0 此外,自从更新以来,解释查询计划现在看起来与我在 C# 3.27.2 中看到的完全一样查询计划:0 0 SEARCH TABLE logs USING INDEX i_Logs (Code=?) 0 0 SEARCH TABLE logs USING INDEX i_Logs (Code=?) 0 0 SEARCH TABLE logs USING INDEX i_Logs (Code=?) 注意:“SEARCH SUBQUERY 1 AS b USING AUTOMATIC COVERING INDEX (SessionID=?)" 部分现在也不见了。 您可以找到在线工具来将 SQL 格式化为人类可读的格式。两个版本之间的变更日志中有一些内容可能适用,但是您现在的查询仍然是一个无法阅读的混乱,我不能肯定地说。 【参考方案1】:非常有趣:将查询转换为视图并运行select * from myview
后,查询速度非常快。解释查询计划现在有以下输出:
id parent notused detail
3 0 0 MATERIALIZE 2
7 3 0 SEARCH TABLE logs USING INDEX i_Logs (Code=?)
44 0 0 MATERIALIZE 3
48 44 0 SEARCH TABLE logs USING INDEX i_Logs (Code=?)
92 0 0 SEARCH TABLE logs USING INDEX i_Logs (Code=?)
112 0 0 SEARCH SUBQUERY 2 AS b USING AUTOMATIC COVERING INDEX (SessionID=?)
140 0 0 SEARCH SUBQUERY 3 AS c USING AUTOMATIC COVERING INDEX (SessionID=?)
157 0 0 USE TEMP B-TREE FOR GROUP BY
259 0 0 USE TEMP B-TREE FOR ORDER BY
我不确定为什么当我使用视图时 EQP 发生了变化,但我现在很高兴,因为它工作得很好而且速度非常快 :-)
非常感谢 @Carlos Cavero 格式化我的代码。
【讨论】:
以上是关于使用 System.Data.SQLite (C#) 的 SQLite 查询比在 SQLiteStudio 中要慢得多的主要内容,如果未能解决你的问题,请参考以下文章
C# 引入Sqlite 未能加载文件或程序集“System.Data.SQLite
C# System.Data.SQLite:并发冲突:UpdateCommand 影响了预期的 1 条记录中的 0 条