For anyone following along
This is a change in SQLite between version 3.7 and 3.8
see http://www.sqlite.org/queryplanner-ng.html
4.0 Hazards Of Upgrading To NGQP
For most applications, upgrading from the legacy query planner to the NGQP requires little thought or effort. Simply replace the older SQLite version with the newer version of SQLite and recompile and the application will run faster. There are no API changes nor modifications to compilation procedures.
But as with any query planner change, upgrading to the NGQP does carry a small risk of introducing performance regressions. The problem here is not that the NGQP is incorrect or buggy or inferior to the legacy query planner. Given reliable information about the selectivity of indices, the NGQP should always pick a plan that is as good or better than before. The problem is that some applications may be using low-quality and low-selectivity indices without having run ANALYZE. The older query planners look at many fewer possible implementations for each query and so they may have stumbled over a good plan by stupid luck. The NGQP, on the other hand, looks at many more query plan possibilities, and it may chose a different query plan that works better in theory, assuming good indices, but which gives a performance regression in practice, because of the shape of the data.
Key points:
The NGQP will always find an equal or better query plan, compared to prior query planners, as long as it has access to accurate ANALYZE data in the SQLITE_STAT1 file.
The NGQP will always find a good query plan as long as the schema does not contain indices that have more than about 10 or 20 rows with the same value in the left-most column of the index.
Not all applications meet these conditions. Fortunately, the NGQP will still usually find good query plans, even without these conditions. However, cases do arise (rarely) where performance regressions can occur.
From the case I modified the example program to do
dim d as new SQLiteDatabase
dim r as RecordSet
d.DatabaseFile = GetOpenFolderItem(".cdb")
dim ts as integer = ticks
if d.Connect then
d.SQLExecute("Analyze")
ts = ticks
r =d.SQLSelect(s)
if R<> nil then MsgBox "Time/records " + str(ticks - ts) + " : " + str(r.RecordCount)
end
Before
R2 695 : 1925
R1.1 7 : 1925
AFTER analyzing
R2 3 : 1925
R1.1 4: 1925