与 MS Access 相比,SQLite 非常慢

标签 sql database sqlite ms-access

正在关注 the advice of fellow SO-ers ,我将我拥有的一个 MS Access 数据库(一个小的,出于测试原因)转换为 SQLite。它有两个表,一个有 5k 个条目,另一个有 50k 个条目。

现在,我将在 QuLimmaQLexeis 下面展示的查询在 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 复制/粘贴)

表 Limma:

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”是唯一的。

最佳答案

您几乎不想在可以使用 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)

请记住,您拥有的每个额外索引在插入时都会产生成本。您必须权衡此成本与指数的 yield 。如果您的表包含静态数据,则没有任何危害。

关于与 MS Access 相比,SQLite 非常慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14588323/

相关文章:

数据库并发 - 处理不同步的对象

Sqlite:选择,加入使用类似的加入字段

iphone - 从 sqlite 检索数据的问题

Mysql全文索引对完全匹配和部分匹配给出相同的分数,为什么?

sql - 如何计算postgres中的中位数

php - 具有多个值的 Wordpress 搜索查询

php - 我需要清理数据库中的数据吗?

sql - 如何将列中的 NULL 值换成最后一个非 NULL 值?

mysql - SQL删除回车

MySQL:使用 LIMIT 的多个 SELECT 语句