Those GeoPackages do have spatial indexes ready but there is a small glitch in how the GeoPackage databases are created. That can be seen by reading the contents of the gpkg_geometry_columns table
SELECT ROWID, "table_name", "column_name", "geometry_type_name", "srs_id", "z", "m" FROM "gpkg_geometry_columns" ORDER BY ROWID
As you can see, all three tables (point, line, polygon) are registered into geometry_columns to include general geometries. QGIS, that can only handle one kind of geometries on the same layer, wants to know what geometries the source data contains and because it can't get that information from the metadata it must read all the geometries and check them one by one and that's slow.
You can create a GeoPackage that suits better for QGIS with these commands:
ogr2ogr -f gpkg test.gpkg railway_EPSG4326.gpkg railway_EPSG4326_point -nlt point
ogr2ogr -f gpkg -append -update test.gpkg railway_EPSG4326.gpkg railway_EPSG4326_line -nlt multilinestring
ogr2ogr -f gpkg -append -update test.gpkg railway_EPSG4326.gpkg railway_EPSG4326_polygon -nlt multipolygon
Now the metadata looks like this
and QGIS can make a connection and add data into the project in seconds while it used to take about one minute with my computer.
With just this database it would be enough to update the GEOMETRY_TYPE_NAME column to have values POINT, LINESTRING and POLYGON but generally that is not a safe
thing to do.
Consider to report these findings to the maintainers of the osmdata.xyz site.
ok unfortunately I performed 2 different resolution activities, and im not sure which activity resolved the problem.
First Action - I had previously run a python script (outside of QGIS) which had completed, but it had used the Geopackage (a different table though). I simply closed this python console window (maybe the console or process that ran inside the console had locked the DB?)
Second action - In QGIS, i went to Database > DB Manager and 'Reconnected' the database. I then reloaded the layer inside of my QGIS session, made an edit and saved. all good.
So - whether it was the first or second action. not sure.
Best Answer
Make a minor but important change and make all edits to happen within one transaction instead of doing one transaction for each row. Transactions are rather expensive for SQLite and therefore also for GeoPackage. Making less but bigger transactions is faster. You can find some numbers from https://stackoverflow.com/questions/1711631/improve-insert-per-second-performance-of-sqlite.
A modified script:
Compare the timings:
With one transaction
Original script without transaction:
I have SSD disk which may explain why your original script is considerably faster for me (15.5 sec vs. 243.56 sec).