Spatialite Backend
The Spatialite backend provides excellent performance for small to medium datasets without requiring external database servers. It leverages SQLite's built-in spatial capabilities with R-tree indexes for efficient filtering.
Spatialite is optimal for datasets < 50,000 features and requires no additional installation - it works out of the box with Python.
Overviewβ
FilterMate's Spatialite backend connects to local SQLite databases with the Spatialite spatial extension. It creates temporary tables with spatial indexes to perform geometric filtering efficiently.
Key Benefitsβ
- β‘ Fast performance on datasets < 50k features
- π§ No setup required - SQLite built into Python
- π¦ Portable - single file database
- πΊοΈ R-tree spatial indexes for optimized searches
- πΎ Local processing - no network overhead
- π Automatic - works immediately with .sqlite files
When Spatialite Backend Is Usedβ
FilterMate automatically selects the Spatialite backend when:
- β Layer source is Spatialite/SQLite with spatial extension
- β
File path points to
.sqlite,.db, or.spatialitefile - β Spatialite extension is available (automatically in Python 3.7+)
For datasets > 50,000 features, FilterMate will display a performance warning suggesting PostgreSQL for better performance.
Installationβ
Prerequisitesβ
- Python 3.7+ (included with QGIS 3.x)
- Spatialite extension (usually pre-installed)
Verificationβ
Spatialite is typically available by default. Verify in QGIS Python Console:
import sqlite3
conn = sqlite3.connect(':memory:')
conn.enable_load_extension(True)
try:
conn.load_extension('mod_spatialite')
print("β Spatialite extension available")
except Exception as e:
# Windows fallback
try:
conn.load_extension('mod_spatialite.dll')
print("β Spatialite extension available (Windows)")
except:
print(f"β Spatialite extension not found: {e}")
conn.close()
Manual Installation (if needed)β
Linuxβ
sudo apt-get install libspatialite7
# or
sudo yum install libspatialite
macOSβ
brew install libspatialite
Windowsβ
Spatialite is included with OSGeo4W QGIS installation. If missing:
- Download from https://www.gaia-gis.it/gaia-sins/windows-bin-amd64/
- Extract
mod_spatialite.dllto Python'sDLLsfolder
Featuresβ
1. Temporary Tablesβ
FilterMate creates temporary tables to store filtered results:
-- Example temporary table created by FilterMate
CREATE TEMP TABLE filtermate_filtered_123 AS
SELECT *
FROM my_layer
WHERE ST_Intersects(
geometry,
(SELECT geometry FROM filter_layer WHERE id = 1)
);
-- Spatial index automatically created
SELECT CreateSpatialIndex('filtermate_filtered_123', 'geometry');
Benefits:
- Fast creation and querying
- Automatic cleanup on session end
- No permanent database modifications
- Memory-efficient for < 50k features
2. R-tree Spatial Indexesβ
Spatialite uses R-tree indexes for spatial queries:
-- Check spatial indexes
SELECT * FROM geometry_columns
WHERE f_table_name = 'my_layer';
-- FilterMate creates R-tree indexes automatically
SELECT CreateSpatialIndex('my_layer', 'geometry');
-- Index is used automatically for spatial queries
SELECT * FROM my_layer
WHERE ST_Intersects(geometry, MakePoint(100, 50, 4326));
R-tree indexes provide 10-100x speedup on spatial queries depending on data distribution.
3. Spatial Operationsβ
Spatialite supports ~90% of PostGIS functions:
| Function | Spatialite | Equivalent |
|---|---|---|
ST_Intersects() | β Full support | Same as PostGIS |
ST_Contains() | β Full support | Same as PostGIS |
ST_Within() | β Full support | Same as PostGIS |
ST_Buffer() | β Full support | Same as PostGIS |
ST_Distance() | β Full support | Same as PostGIS |
ST_Area() | β Full support | Same as PostGIS |
ST_Length() | β Full support | Same as PostGIS |
ST_Union() | β Full support | Same as PostGIS |
ST_Difference() | β Full support | Same as PostGIS |
ST_Intersection() | β Full support | Same as PostGIS |
Example Query:
-- Find all features within 100m of a point
SELECT *
FROM my_layer
WHERE ST_Intersects(
geometry,
ST_Buffer(MakePoint(100, 50, 4326), 100)
);
4. Database Optimizationβ
FilterMate applies several optimizations:
- VACUUM - Reclaims unused space
- ANALYZE - Updates query statistics
- Spatial index hints - Forces R-tree usage
- Transaction batching - Groups operations
Example:
-- After creating temp table
ANALYZE filtermate_filtered_123;
-- Vacuum on cleanup
VACUUM;
Configurationβ
Database Locationβ
Spatialite databases are single files:
/path/to/data/
βββ my_data.sqlite # Main database
βββ my_data.sqlite-shm # Shared memory (auto-created)
βββ my_data.sqlite-wal # Write-ahead log (auto-created)
Cache Settingsβ
Optimize Spatialite for performance:
-- In QGIS Python Console (per-session)
import sqlite3
conn = sqlite3.connect('/path/to/data.sqlite')
-- Increase cache size (in KB)
conn.execute("PRAGMA cache_size = 100000") -- 100MB cache
-- Enable memory-mapped I/O
conn.execute("PRAGMA mmap_size = 268435456") -- 256MB mmap
-- WAL mode for better concurrency
conn.execute("PRAGMA journal_mode = WAL")
conn.close()
Performance Settingsβ
For optimal performance in config/config.json:
{
"SPATIALITE": {
"cache_size_kb": 100000,
"enable_mmap": true,
"journal_mode": "WAL",
"vacuum_on_cleanup": true
}
}
Usageβ
Basic Filteringβ
- Load Spatialite layer in QGIS (Layer β Add Layer β Vector)
- Open FilterMate plugin
- Configure filter options
- Click "Apply Filter"
FilterMate automatically:
- Detects Spatialite backend
- Creates temporary table with spatial index
- Adds filtered layer to QGIS
- Displays backend indicator: [SQLite]
Creating Spatialite Databaseβ
From existing data:
# In QGIS Python Console
from qgis.core import QgsVectorFileWriter
layer = iface.activeLayer()
options = QgsVectorFileWriter.SaveVectorOptions()
options.driverName = "SQLite"
options.layerName = "my_layer"
options.datasourceOptions = ["SPATIALITE=YES"]
QgsVectorFileWriter.writeAsVectorFormatV3(
layer,
"/path/to/output.sqlite",
QgsCoordinateTransformContext(),
options
)
Batch Processingβ
For multiple Spatialite layers:
# FilterMate handles multiple layers efficiently
# Each gets its own temporary table
Performance Tuningβ
For Small Datasets (< 10k features)β
- No special configuration needed
- Use default settings
- Performance comparable to PostgreSQL
For Medium Datasets (10k - 50k features)β
-
Increase cache size:
PRAGMA cache_size = 50000; -- 50MB -
Enable WAL mode:
PRAGMA journal_mode = WAL; -
Create spatial indexes manually if missing:
SELECT CreateSpatialIndex('my_layer', 'geometry');
For Large Datasets (50k - 500k features)β
Consider using PostgreSQL backend for better performance. Spatialite can handle these sizes but will be slower.
If using Spatialite:
-
Maximize cache:
PRAGMA cache_size = 200000; -- 200MB -
Enable memory-mapped I/O:
PRAGMA mmap_size = 536870912; -- 512MB -
Run VACUUM ANALYZE:
VACUUM;
ANALYZE;
Limitationsβ
Compared to PostgreSQLβ
| Feature | Spatialite | PostgreSQL |
|---|---|---|
| Max practical size | ~500k features | 10M+ features |
| Concurrent access | Limited | Excellent |
| Server-side ops | β No | β Yes |
| Parallel queries | β No | β Yes |
| Network access | β No (file-based) | β Yes |
| Transaction isolation | Basic | Advanced |
| Query optimization | Good | Excellent |
Known Limitationsβ
- Single-user - File locking prevents true concurrent access
- No parallel processing - Queries run single-threaded
- Memory constraints - Large operations may consume lots of RAM
- No remote access - Must have local file access
If you regularly work with > 50k features, consider migrating to PostgreSQL for 5-10x performance improvement.
Troubleshootingβ
Issue: "Spatialite extension not found"β
Symptom: Error when opening Spatialite database
Solution:
-
Check Python environment:
import sqlite3
print(sqlite3.sqlite_version) # Should be 3.7+ -
Try alternative extension names:
conn.load_extension('mod_spatialite') # Linux/macOS
conn.load_extension('mod_spatialite.dll') # Windows
conn.load_extension('libspatialite') # Alternative -
Install Spatialite (see Installation section)
Issue: "Slow queries despite spatial index"β
Symptom: Filtering takes longer than expected
Solution:
-
Verify spatial index exists:
SELECT * FROM geometry_columns WHERE f_table_name = 'my_layer'; -
Check R-tree index:
SELECT * FROM sqlite_master
WHERE type = 'table' AND name LIKE 'idx_%_geometry'; -
Rebuild spatial index:
SELECT DisableSpatialIndex('my_layer', 'geometry');
SELECT CreateSpatialIndex('my_layer', 'geometry'); -
Run ANALYZE:
ANALYZE my_layer;
Issue: "Database is locked"β
Symptom: Cannot write to database
Solution:
- Close other QGIS instances using the same file
- Check for orphaned lock files (
.sqlite-shm,.sqlite-wal) - Switch to WAL mode for better concurrency:
PRAGMA journal_mode = WAL;
Issue: "Out of memory"β
Symptom: Query fails on large dataset
Solution:
-
Reduce cache size (paradoxically helps sometimes):
PRAGMA cache_size = 10000; -- 10MB -
Switch to PostgreSQL for datasets > 100k features
-
Filter in stages - break up large operations
Performance Benchmarksβ
Real-world performance on typical hardware (Core i7, 16GB RAM, SSD):
| Dataset Size | Features | Spatialite | PostgreSQL | Ratio |
|---|---|---|---|---|
| Small | 5,000 | 0.4s | 0.3s | 1.3x slower |
| Medium | 50,000 | 8.5s | 1.2s | 7x slower |
| Large | 500,000 | 65s | 8.4s | 8x slower |
| Very Large | 5,000,000 | Timeout | 45s | Not viable |
Spatial Operations (50k features):
| Operation | Time | vs PostgreSQL |
|---|---|---|
| Intersects | 8.2s | 6x slower |
| Contains | 9.1s | 5x slower |
| Buffer (10m) + Intersects | 12.5s | 5x slower |
| Complex expression | 18.3s | 6x slower |
Best Practicesβ
β Doβ
- Use Spatialite for < 50k features - excellent performance
- Create spatial indexes - huge performance boost
- Use WAL journal mode - better concurrency
- Run VACUUM periodically - maintains performance
- Backup before bulk operations - easy with single file
β Don'tβ
- Don't use for > 500k features - too slow
- Don't forget spatial indexes - 10-100x performance penalty
- Don't open same file in multiple processes - database locking
- Don't disable R-tree indexes - spatial queries will be slow
Migrating to PostgreSQLβ
If your Spatialite database grows too large:
Option 1: QGIS DB Managerβ
- Open DB Manager (Database β DB Manager)
- Select Spatialite database
- Right-click layer β Export to PostgreSQL
- Configure connection and import
Option 2: Command Line (ogr2ogr)β
ogr2ogr -f PostgreSQL \
PG:"host=localhost dbname=mydb user=myuser password=mypass" \
my_data.sqlite \
-lco GEOMETRY_NAME=geometry \
-lco SPATIAL_INDEX=GIST
Option 3: Python Scriptβ
from qgis.core import QgsVectorLayer, QgsDataSourceUri
# Load Spatialite layer
sqlite_layer = QgsVectorLayer(
"/path/to/data.sqlite|layername=my_layer",
"sqlite_layer",
"ogr"
)
# Export to PostgreSQL
uri = QgsDataSourceUri()
uri.setConnection("localhost", "5432", "mydb", "user", "pass")
uri.setDataSource("public", "my_layer", "geometry")
# Use QGIS processing or DB Manager export
See Alsoβ
- Backends Overview - Multi-backend architecture
- Backend Selection - Automatic selection logic
- PostgreSQL Backend - For larger datasets
- Performance Comparison - Detailed benchmarks
- Troubleshooting - Common issues
Technical Detailsβ
Database Structureβ
FilterMate creates temporary tables with this structure:
-- Temporary filtered table
CREATE TEMP TABLE filtermate_filtered_123 (
fid INTEGER PRIMARY KEY,
geometry BLOB,
-- Original attribute columns
...
);
-- Register geometry column
SELECT RecoverGeometryColumn(
'filtermate_filtered_123',
'geometry',
4326, -- SRID
'POLYGON',
'XY'
);
-- Create spatial index
SELECT CreateSpatialIndex('filtermate_filtered_123', 'geometry');
Supported Functionsβ
QGIS expressions translated to Spatialite SQL:
| QGIS Expression | Spatialite Function |
|---|---|
intersects() | ST_Intersects() |
contains() | ST_Contains() |
within() | ST_Within() |
buffer() | ST_Buffer() |
distance() | ST_Distance() |
area() | ST_Area() |
length() | ST_Length() |
Cleanupβ
FilterMate automatically cleans up temporary tables:
-- On plugin close or filter clear
DROP TABLE IF EXISTS filtermate_filtered_123;
-- Reclaim space
VACUUM;
Last Updated: December 8, 2025
Plugin Version: 2.2.3
Spatialite Support: SQLite 3.7+ with Spatialite 4.3+