Hello,
I have a curiously slow query, and I?m not sure if it?s caused by something I?m
doing (most likely) or by something odd in sqlite (almost certainly not).
The tables we have are:
Appointment(Appointment_UUID, Appointment_TxnUUID, Appointment_StartDate, and
other columns)
Txn(Txn_UUID, Txn_Created, Txn_Reference amongst others).
TxnCalc(TxnCalc_TxnUUID, TxnCalc_Date amongst others).
The query I am running is this (using a prepared statement):
SELECT TxnCalc_TxnUUID AS Txn_UUID
FROM (
SELECT Txn.Txn_UUID AS TempTxn_UUID
FROM Txn
LEFT JOIN Appointment ON Appointment_TxnUUID=Txn_UUID
WHERE ( date( Appointment_StartDate ) >= trim( ? ) AND date(
Appointment_StartDate ) <= trim( ? ) ) )
AS SubQueryResult,
TxnCalc,
Txn
WHERE TxnCalc_TxnUUID=TempTxn_UUID
AND TxnCalc_TxnUUID=Txn_UUID
GROUP BY TxnCalc_TxnUUID
ORDER BY TxnCalc_Date DESC,
Txn_Reference DESC,
Txn_Created DESC
If possible, I?d like you to ignore the structure of the query, which isn?t
quite as good as it could be, I know; it?s the next bit that?s curious.
We have indexes on Txn_UUID, TxnCalc_TxnUUID, Appointment_UUID - nothing
controversial there - and also on Appointment_TxnUUID. That field has many,
many blank values (as Appointments are most often linked to other things) and
only a very few non-blank values. They?re blank (ie ??) and not NULL, if that
makes a difference.
When running that query using SQLite 3.7.14.1, it takes around 230ms to run.
The query plan is this:
SCAN TABLE Txn (~3670 rows)
SEARCH TABLE Appointment USING AUTOMATIC COVERING INDEX (Appointment_TxnUUID=?)
(~5 rows)
SEARCH TABLE TxnCalc USING INDEX idx_TxnCalc_TxnUUID (TxnCalc_TxnUUID=?) (~1
rows)
SEARCH TABLE Txn USING INDEX idx_Txn_UUID (Txn_UUID=?) (~1 rows)
USE TEMP B-TREE FOR GROUP BY
USE TEMP B-TREE FOR ORDER BY
Interestingly, it?s not using the index which we created for the SEARCH TABLE
Appointment.
When running the query using SQLite 3.8.8, it takes around 1600ms to run. The
query plan is this:
SCAN TABLE Txn USING COVERING INDEX idx_Txn_UUID
SCAN TABLE Appointment
SEARCH TABLE TxnCalc USING INDEX idx_TxnCalc_TxnUUID (TxnCalc_TxnUUID=?)
SEARCH TABLE Txn USING INDEX idx_Txn_UUID (Txn_UUID=?)
USE TEMP B-TREE FOR GROUP BY
USE TEMP B-TREE FOR ORDER BY
ie no index on Appointment at all.
Now for the curious bit. If I drop the index which I made, and recreate it
using the exact same code with which I created it when I made my database -
CREATE INDEX idx_Appointment_TxnUUID ON Appointment(Appointment_TxnUUID) -
using sqlite 3.7.14.1 the query is down to 12ms, and using 3.8.8, it?s down to
4ms.
With the database in its ?slow? state, running ANALYZE makes no difference.
Likewise, REINDEX idx_Appointment_TxnUUID makes no difference.
Background: I create the database, make the indexes, and then do a bunch of
INSERTs into it, along with UPDATES, DELETES etc. - basically using it as a
normal workhorse database.
So, the question, after this somewhat long explanation: should deleting and
recreating an index like this cause such a massive performance improvement? If
so, why? What am I doing wrong in the first place?
Thanks in advance for your assistance,
Hamish
--
Hamish Symington
07815 081282 : info at hamishsymington.com
I also set custom cryptic crosswords: www.customcrypticcrosswords.com
(@CustomCryptics on Twitter)