Запрос SQLite значительно медленнее с System.Data.SQLite (C #), чем в SQLiteStudio - PullRequest
1 голос
/ 18 марта 2019

У меня есть запрос, который запускает несколько объединений в одной таблице. Он присоединяется к 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.

При выполнении того же запроса из моего C # через System.Data.SQLite для той же базы данных запрос значительно медленнее (примерно в 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=?)

Обратите внимание, что не используется автоматический индекс покрытия.

Я попытался использовать Analyze и также явно установил automatic_index = true для соединения SQLite, но это не повлияло на план запроса.

Запрос 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. Примечание: «ИНДЕКС АВТОМАТИЧЕСКОГО ПОКРЫТИЯ» теперь также отсутствует.

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=?)

1 Ответ

0 голосов
/ 18 марта 2019

Очень интересно: как только я преобразовал запрос в представление и запустил 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 за форматирование моего кода.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...