与 MS Access 相比,SQLite 非常慢
Posted
技术标签:
【中文标题】与 MS Access 相比,SQLite 非常慢【英文标题】:SQLite terribly slow compared to MS Access 【发布时间】:2013-01-29 17:10:40 【问题描述】:在the advice of fellow SO-ers 之后,我将我拥有的一个 MS Access 数据库(一个小的,出于测试原因)转换为 SQLite。它有两个表,一个有 5k 条目,另一个有 50k 条目。
现在,我将在 QuLimma 和 QLexeis 下面展示的查询使用 Access 大约需要 60 毫秒(以下函数的总时间),而使用 SQLite 则需要 830 毫秒。
Dim i As Integer
Dim ms As Integer
ResultPin(0) = ""
ResultPin(1) = ""
ResultPin(2) = ""
ResultPin(3) = ""
ResultPin(4) = ""
i = 0
Multichoice = 0
ms = 0
Dim rsTblEntries As ADODB.Recordset
Set rsTblEntries = New ADODB.Recordset
Dim QuLimma As String, QLexeis As String
QuLimma = "SELECT Words.limma, Words.limmabody, Words.limmapro " & _
"FROM Words " & _
"GROUP BY Words.limma, Words.limmabody, Words.limmapro " & _
"HAVING (((Words.limma)='" & StrLexeis & "'));"
QLexeis = "SELECT Limma.limmalexeis, Words.limma, Limma.limmabody, Words.limmapro, Limma.limmaexp " & _
"FROM Limma INNER JOIN Words ON Limma.limmabody = Words.limmabody " & _
"GROUP BY Limma.limmalexeis, Words.limma, Limma.limmabody, Words.limmapro, Limma.limmaexp " & _
"HAVING (((Limma.limmalexeis)='" & StrLexeis & "'));"
rsTblEntries.Open QuLimma, CnDataParSQLite ', adOpenStatic, adLockOptimistic
If rsTblEntries.EOF = True Then
rsTblEntries.Close
rsTblEntries.Open QLexeis, CnDataParSQLite ', adOpenStatic, adLockOptimistic
If rsTblEntries.EOF = True Then
SearchQParagSQLite = False
Else
SearchQParagSQLite = True
Do While rsTblEntries.EOF = False
ms = ms + 1
rsTblEntries.MoveNext
Loop
rsTblEntries.MoveFirst
If ms > 1 Then
Do While rsTblEntries.EOF = False
ResultTemp(0, i) = rsTblEntries.Fields("limma").Value & "" 'rsWordPar!limma
ResultTemp(1, i) = rsTblEntries.Fields("limmalexeis").Value & "" 'rsWordPar!limmalexeis
ResultTemp(2, i) = rsTblEntries.Fields("limmabody").Value 'rsWordPar!limmabody
If IsNull(rsTblEntries.Fields("limmapro").Value) = False Then ResultTemp(3, i) = rsTblEntries.Fields("limmapro").Value 'rsWordPar!limmapro
rsTblEntries.MoveNext
i = i + 1
Multichoice = 1
Loop
Else
Do While rsTblEntries.EOF = False
ResultPin(0) = rsTblEntries.Fields("limma").Value & "" 'rsWordPar!limma
ResultPin(1) = rsTblEntries.Fields("limmalexeis").Value & "" 'rsWordPar!limmalexeis
ResultPin(2) = rsTblEntries.Fields("limmabody").Value 'rsWordPar!limmabody
If IsNull(rsTblEntries.Fields("limmapro").Value) = False Then ResultPin(3) = rsTblEntries.Fields("limmapro").Value 'rsWordPar!limmapro
rsTblEntries.MoveNext
Multichoice = 0
Loop
End If
End If
Else
SearchQParagSQLite = True
rsTblEntries.MoveFirst
Do While rsTblEntries.EOF = False
ResultPin(0) = rsTblEntries.Fields("limma").Value & "" 'rsWordPar!limma
ResultPin(1) = "#"
ResultPin(2) = rsTblEntries.Fields("limmabody").Value 'rsWordPar!limmabody
If IsNull(rsTblEntries.Fields("limmapro").Value) = False Then ResultPin(3) = rsTblEntries.Fields("limmapro").Value 'rsWordPar!limmapro
rsTblEntries.MoveNext
i = i + 1
Loop
End If
i = 0
rsTblEntries.Close
Set rsTblEntries = Nothing
带连接字符串:
CnDataParSQLite.ConnectionString = "DRIVER=SQLite3 ODBC Driver;" & _
"Database=" & strDataPath & "u.sl3;LongNames=0;Timeout=1000;NoTXN=0;SyncPragma=NORMAL;StepAPI=0;"
CnDataParSQLite.Open
现在,在有人问“60 毫秒不够快吗?”之前,我想说我这样做是因为我有其他 Access 文件和查询需要 3-4 秒,并且想降低它们,所以是的,我希望在这个中从 60 毫秒减少到 30 毫秒或更少。
是我配置错误还是只是 SQLite 没有更快?我检查了,两者都返回正确的结果,没有奇怪的循环问题。
编辑:大部分时间都被第二个查询所消耗。
编辑 2:(从 db.sql 复制/粘贴)
表利马:
CREATE TABLE Limma ( id INTEGER PRIMARY KEY, limmabody INTEGER DEFAULT 0, limmalexeis VARCHAR2(100), limmastat VARCHAR2(50), limmaexp VARCHAR2(250));
INSERT INTO Limma VALUES (1, 1, 'υψικάμινος', 'ΣΠ', NULL);
INSERT INTO Limma VALUES (2, 1, 'υψίκορμος', 'ΣΠ', NULL);
INSERT INTO Limma VALUES (3, 1, 'υψίπεδο', 'ΑΠ', '<αρχ. υψίπεδον, ουδ. του επιθ. υψίπεδος<ύψι "ψηλά" + πέδον');
总计:64k 个条目
表词:
CREATE TABLE Words ( id INTEGER PRIMARY KEY, limma VARCHAR2(100), limmabody INTEGER DEFAULT 0, limmapro VARCHAR2(200));
INSERT INTO Words VALUES (1, 'υψι (αχώριστο μόριο)', 1, NULL);
INSERT INTO Words VALUES (2, 'ομο (αχώριστο μόριο)', 2, NULL);
INSERT INTO Words VALUES (3, 'διχο (αχώριστο μόριο)', 3, NULL);
总计:6k 个条目
第一个字段“id”是唯一的。
【问题讨论】:
你说你去了Sqlite,但是你的表定义看起来像Oracle。我认为 Sqlite 没有“Varchar2”数据类型。 请运行“从 SYS.NLS_DATABASE_PARAMETERS 中选择值,其中 PARAMETER = 'NLS_CHARACTERSET'”并发布输出。如果您的数据库未设置为使用 unicode 字符集,您可能需要更改表定义并重新开始。 @LoveLearn,摘自转换后的中间 .sql 文件( ms 访问 -> .sql -> sqlite3 您绝对应该做一些研究,以确保您的列正确存储您的 unicode 值。如果是,那么一切都很好,但如果不是,您需要更新您的数据类型。这可能没问题,但如果他们不这样做,那可能会有些灾难性。 如果您能够加快 Access 中的查询速度,您还会有兴趣切换到 SQLite 吗?这令人困惑。 【参考方案1】:您几乎从不想在可以使用 WHERE 条件的地方使用 HAVING。您正在评估所有可能的结果,然后在聚合后将它们剔除。您主要想使用 HAVING 标准,您试图根据汇总结果进行剔除。在这种情况下,您可以通过将 HAVING 逻辑移动到聚合之前的 WHERE 条件来实现相同的目的。这应该会大大加快您的查询速度。
也不需要使用 GROUP BY 逻辑,因为您没有返回任何聚合,只需使用 DISTINCT。
我会这样写:
QuLimma = "SELECT DISTINCT Words.limma, Words.limmabody, Words.limmapro " & _
"FROM Words " & _
"WHERE Words.limma ='" & StrLexeis & "';"
QLexeis = "SELECT DISTINCT Limma.limmalexeis, Words.limma, Limma.limmabody, Words.limmapro, Limma.limmaexp " & _
"FROM Limma INNER JOIN Words ON Limma.limmabody = Words.limmabody " & _
"WHERE Limma.limmalexeis ='" & StrLexeis & "';"
对于使用您的表架构的这两个查询,这些索引应该优化查询:
CREATE NONCLUSTERED INDEX ix_words_1 ON Words (Limma) INCLUDE (Limmabody, Limmapro)
CREATE NONCLUSTERED INDEX ix_words_2 ON Words (Limmabody) INCLUDE (Limma, Limmapro)
CREATE NONCLUSTERED INDEX ix_limma_1 ON Limma (Limmabody, Limmalexeis) INCLUDE (Limmaexp)
请记住,您拥有的每个附加索引在插入时都会产生费用。您必须权衡此成本与索引的收益。如果您的表包含静态数据,那么没有什么坏处。
【讨论】:
感谢您的回复。也许我还缺少表索引?我刚刚将数据库从 access 转换为 sqlite,但我不知道是否应该索引它以及如何。 如果你没有任何索引,你肯定需要在你的表上添加索引。我无法从您的专栏中确切知道它们的用途。您能否提供完整的表定义并描述每列是什么?我自己或其他人应该能够为您提供包含此信息的复制粘贴“CREATE INDEX”语句。 我用表格定义和解释更新了我的初始帖子。非常感谢! 每张表的“id”列有什么意义,你有没有查询或过滤过? 它只是一个自动编号,有时会被查询(不是在这两个特定查询中)以上是关于与 MS Access 相比,SQLite 非常慢的主要内容,如果未能解决你的问题,请参考以下文章
MS Access 中通过 ODBC 连接 MS SQL 表的查询非常慢
MS Access 直通查询 - 使用 ODBC 连接字符串时非常慢,手动选择数据源时速度快 - 问题出在哪里