1. 首页 > sqlite教程 > 正文

sqlite教程FG016-R树索引、空间数据与虚拟表

本文档风哥主要介绍sqlite数据库R树索引、空间数据与虚拟表相关知识,风哥教程参考sqlite官方文档R-Tree Extension、Virtual Tables等内容编写,适合DBA人员和开发人员在学习和测试中使用。

Part01-基础概念与理论知识

1.1 sqlite数据库R树索引原理

R树是一种空间索引结构,用于高效处理空间查询。更多视频教程www.fgedu.net.cn

sqlite数据库R树索引原理:

R树特点:
├── 空间索引:专门处理多维数据
├── 范围查询:高效的范围搜索
├── 层次结构:树形索引结构
└── B树变体:类似B树的平衡树

R树应用场景:
├── 地理位置查询
├── 地图应用
├── 空间数据分析
├── CAD/GIS系统
├── 游戏碰撞检测
└── 图像检索

R树维度支持:
├── R-Tree 1-5维
├── 最常用:2维(经纬度)
├── 3维:空间坐标
└── 高维:特征向量

R树索引结构:
┌─────────────────────────────────────────┐
│ 根节点(大范围) │
│ / \ │
│ 中间节点 中间节点 │
│ / \ / \ │
│ 叶子节点 叶子节点 叶子节点 叶子节点 │
│ (实际数据矩形) │
└─────────────────────────────────────────┘

R树查询类型:
├── 包含查询:完全包含指定范围
├── 相交查询:与指定范围相交
├── 最近邻查询:距离最近的点
└── 范围查询:指定范围内的点

1.2 sqlite数据库空间数据处理

空间数据处理是地理信息系统的基础,学习交流加群风哥微信: itpux-com

sqlite数据库空间数据处理:

空间数据类型:
├── 点:经纬度坐标
├── 线:路径、道路
├── 多边形:区域、建筑
└── 矩形:边界框

坐标系统:
├── WGS84:GPS坐标(经纬度)
├── GCJ02:国测局坐标
├── BD09:百度坐标
└── 投影坐标:平面坐标

空间运算:
├── 距离计算:两点间距离
├── 范围计算:边界框
├── 包含判断:点是否在区域内
└── 相交判断:区域是否相交

距离计算公式(Haversine):
distance = 2 * R * arcsin(sqrt(
sin²((lat2-lat1)/2) +
cos(lat1) * cos(lat2) * sin²((lon2-lon1)/2)
))

其中R为地球半径(6371km)

常用空间查询:
├── 附近搜索:指定半径内的点
├── 区域搜索:矩形范围内的点
├── 路径规划:最近点查找
└── 热力图:密度分析

1.3 sqlite数据库虚拟表机制

虚拟表是sqlite的扩展机制,可以像普通表一样查询外部数据。更多学习教程公众号风哥教程itpux_com

sqlite数据库虚拟表机制:

虚拟表特点:
├── 像表一样查询
├── 数据不在数据库中
├── 通过模块实现
└── 支持增删改查

内置虚拟表:
├── fts3/fts4/fts5:全文检索
├── rtree:空间索引
├── dbstat:数据库统计
├── csv:CSV文件
└── json_each/json_tree:JSON遍历

虚拟表模块:
├── xCreate:创建表
├── xConnect:连接表
├── xBestIndex:查询优化
├── xOpen/xClose:游标管理
├── xFilter:过滤数据
├── xNext:移动游标
├── xColumn:获取列值
├── xRowid:获取行ID
└── xUpdate:更新数据

创建虚拟表语法:
CREATE VIRTUAL TABLE table_name USING module_name(args);

虚拟表应用场景:
├── 外部数据源访问
├── 自定义索引结构
├── 数据格式转换
├── API数据封装
└── 实时数据查询

Part02-生产环境规划与建议

2.1 sqlite数据库R树应用规划

合理的R树规划可以确保空间查询高效。风哥提示:R树索引适合读多写少的场景。

sqlite数据库R树应用规划:

1. 维度选择
├── 2维:经纬度(最常用)
├── 3维:空间坐标
└── 根据实际需求选择

2. 数据精度
├── 经纬度:6位小数约1米精度
├── 根据需求确定精度
└── 避免过度精度

3. 索引维护
├── 批量导入后重建
├── 定期优化
└── 监控索引大小

4. 查询优化
├── 使用边界框过滤
├── 限制返回数量
└── 合理设置查询范围

R树性能特点:
├── 查询:O(log n)
├── 插入:O(log n)
├── 删除:O(log n)
└── 空间:约1.5-2倍数据大小

Part03-生产环境项目实施方案

3.1 sqlite数据库R树索引实战

R树索引创建示例:
— 创建位置表
CREATE TABLE fgedu_locations (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
type TEXT,
address TEXT
);

— 创建R树虚拟表(2维)
CREATE VIRTUAL TABLE fgedu_location_rtree USING rtree(
id,
minLng, maxLng,
minLat, maxLat
);

— 插入位置数据
INSERT INTO fgedu_locations (id, name, type, address) VALUES
(1, ‘风哥培训中心’, ‘教育’, ‘北京市海淀区’),
(2, ‘ITPUX数据中心’, ‘数据中心’, ‘北京市朝阳区’),
(3, ‘sqlite研发中心’, ‘研发’, ‘上海市浦东新区’);

— 插入R树索引
INSERT INTO fgedu_location_rtree VALUES
(1, 116.310003, 116.310003, 39.959003, 39.959003),
(2, 116.480003, 116.480003, 39.920003, 39.920003),
(3, 121.500003, 121.500003, 31.220003, 31.220003);

— 范围查询:查找矩形范围内的位置
sqlite> SELECT l.name, l.type, r.minLng, r.minLat
…> FROM fgedu_locations l
…> JOIN fgedu_location_rtree r ON l.id = r.id
…> WHERE r.minLng >= 116.0 AND r.maxLng <= 117.0 ...> AND r.minLat >= 39.5 AND r.maxLat <= 40.0; 风哥培训中心|教育|116.310003|39.959003 ITPUX数据中心|数据中心|116.480003|39.920003 -- 附近搜索:查找指定点附近的位置 -- 北京天安门坐标:116.397128, 39.903738 -- 搜索范围:约5公里(经度±0.05,纬度±0.05) sqlite> SELECT l.name, l.address,
…> ((r.minLng – 116.397128) * (r.minLng – 116.397128) +
…> (r.minLat – 39.903738) * (r.minLat – 39.903738)) as distance
…> FROM fgedu_locations l
…> JOIN fgedu_location_rtree r ON l.id = r.id
…> WHERE r.minLng >= 116.347128 AND r.maxLng <= 116.447128 ...> AND r.minLat >= 39.853738 AND r.maxLat <= 39.953738 ...> ORDER BY distance
…> LIMIT 10;
风哥培训中心|北京市海淀区|0.0032
ITPUX数据中心|北京市朝阳区|0.0125

3.2 sqlite数据库空间查询实战

空间查询函数实现:
— 创建距离计算函数(需要在应用层实现)
— 这里使用简化的欧几里得距离

— 创建视图计算距离
CREATE VIEW v_nearby_locations AS
SELECT
l.id,
l.name,
l.type,
l.address,
r.minLng as lng,
r.minLat as lat
FROM fgedu_locations l
JOIN fgedu_location_rtree r ON l.id = r.id;

— 查询指定坐标附近的点(使用R树过滤)
— 目标坐标:116.397128, 39.903738
— 搜索半径:约10公里
sqlite> SELECT
…> name,
…> address,
…> lng,
…> lat,
…> ROUND((lng – 116.397128) * (lng – 116.397128) +
…> (lat – 39.903738) * (lat – 39.903738), 6) as dist_sq
…> FROM v_nearby_locations
…> WHERE lng BETWEEN 116.297128 AND 116.497128
…> AND lat BETWEEN 39.803738 AND 40.003738
…> ORDER BY dist_sq
…> LIMIT 5;
风哥培训中心|北京市海淀区|116.310003|39.959003|0.0032
ITPUX数据中心|北京市朝阳区|116.480003|39.920003|0.0125

— 创建触发器自动同步R树
CREATE TRIGGER tr_location_insert
AFTER INSERT ON fgedu_locations
BEGIN
— 需要在应用层提供坐标
— INSERT INTO fgedu_location_rtree VALUES (NEW.id, lng, lng, lat, lat);
END;

CREATE TRIGGER tr_location_delete
AFTER DELETE ON fgedu_locations
BEGIN
DELETE FROM fgedu_location_rtree WHERE id = OLD.id;
END;

3.3 sqlite数据库虚拟表实战

CSV虚拟表示例:
— 创建CSV虚拟表
CREATE VIRTUAL TABLE fgedu_csv_data USING csv(
filename = ‘/sqlite/data/users.csv’,
schema = ‘CREATE TABLE x(id INTEGER, name TEXT, email TEXT)’,
columns = 3
);

— 查询CSV数据
sqlite> SELECT * FROM fgedu_csv_data LIMIT 5;
1|张三|zhangsan@fgedu.net.cn
2|李四|lisi@fgedu.net.cn
3|王五|wangwu@fgedu.net.cn

— JSON虚拟表
sqlite> SELECT * FROM json_each(‘[“a”,”b”,”c”]’);
0|a
1|b
2|c

sqlite> SELECT * FROM json_each(‘{“name”:”风哥”,”age”:35}’);
name|风哥
age|35

— dbstat虚拟表(数据库统计)
sqlite> SELECT name, pgsize, pgcount FROM dbstat ORDER BY pgcount DESC;
fgedu_users|4096|128
fgedu_orders|4096|64
sqlite_master|4096|1

— 创建自定义虚拟表(示例)
— 需要编写C代码实现虚拟表模块
— CREATE VIRTUAL TABLE my_vtable USING my_module(…);

Part04-生产案例与实战讲解

4.1 sqlite数据库位置查询案例

位置服务完整案例:
/*
* location_service.c
* from:www.itpux.com.qq113257174.wx:itpux-com
* web: http://www.fgedu.net.cn
*/

#include <stdio.h>
#include <sqlite3.h>
#include <math.h>

#define EARTH_RADIUS 6371.0

// 计算两点距离(公里)
double haversine(double lat1, double lon1, double lat2, double lon2) {
double dLat = (lat2 – lat1) * M_PI / 180.0;
double dLon = (lon2 – lon1) * M_PI / 180.0;
lat1 = lat1 * M_PI / 180.0;
lat2 = lat2 * M_PI / 180.0;

double a = sin(dLat/2) * sin(dLat/2) +
cos(lat1) * cos(lat2) * sin(dLon/2) * sin(dLon/2);
double c = 2 * atan2(sqrt(a), sqrt(1-a));

return EARTH_RADIUS * c;
}

// 搜索附近位置
int search_nearby(sqlite3 *db, double lat, double lng, double radius_km) {
sqlite3_stmt *stmt;
char sql[512];

// 计算边界框(约1度≈111公里)
double lat_delta = radius_km / 111.0;
double lng_delta = radius_km / (111.0 * cos(lat * M_PI / 180.0));

snprintf(sql, sizeof(sql),
“SELECT l.id, l.name, l.address, r.minLng, r.minLat ”
“FROM fgedu_locations l ”
“JOIN fgedu_location_rtree r ON l.id = r.id ”
“WHERE r.minLng >= ? AND r.maxLng <= ? " " AND r.minLat >= ? AND r.maxLat <= ?"); sqlite3_prepare_v2(db, sql, -1, &stmt, NULL); sqlite3_bind_double(stmt, 1, lng - lng_delta); sqlite3_bind_double(stmt, 2, lng + lng_delta); sqlite3_bind_double(stmt, 3, lat - lat_delta); sqlite3_bind_double(stmt, 4, lat + lat_delta); printf("\n=== Nearby Locations (radius=%.1fkm) ===\n", radius_km); printf("%-5s %-20s %-30s %s\n", "ID", "Name", "Address", "Distance"); printf("--------------------------------------------------------\n"); int count = 0; while (sqlite3_step(stmt) == SQLITE_ROW) { int id = sqlite3_column_int(stmt, 0); const char *name = (const char*)sqlite3_column_text(stmt, 1); const char *address = (const char*)sqlite3_column_text(stmt, 2); double loc_lng = sqlite3_column_double(stmt, 3); double loc_lat = sqlite3_column_double(stmt, 4); double distance = haversine(lat, lng, loc_lat, loc_lng); if (distance <= radius_km) { printf("%-5d %-20s %-30s %.2fkm\n", id, name, address, distance); count++; } } printf("--------------------------------------------------------\n"); printf("Found %d locations\n", count); sqlite3_finalize(stmt); return count; } int main() { sqlite3 *db; sqlite3_open("/sqlite/fgdata/fgedudb.db", &db); // 搜索天安门附近5公里 search_nearby(db, 39.903738, 116.397128, 5.0); sqlite3_close(db); return 0; }

Part05-风哥经验总结与分享

5.1 sqlite数据库R树最佳实践

sqlite数据库R树最佳实践:

1. 数据建模
├── 主表存储属性
├── R树存储坐标
├── 使用触发器同步
└── 定期重建索引

2. 查询优化
├── 先用R树过滤
├── 再计算精确距离
├── 限制返回数量
└── 使用边界框

3. 性能考虑
├── 批量导入后重建
├── 监控索引大小
├── 定期VACUUM
└── 合理设置维度

4. 应用建议
├── 位置服务
├── 地图应用
├── 空间分析
└── 游戏开发

风哥总结:R树索引是sqlite处理空间数据的利器,适合位置服务、地图应用等场景。虚拟表机制提供了强大的扩展能力,可以像查询普通表一样访问外部数据。生产环境建议合理设计空间数据模型,使用R树加速范围查询,并注意索引的维护和优化。

本文由风哥教程整理发布,仅用于学习测试使用,转载注明出处:http://www.fgedu.net.cn/10327.html

联系我们

在线咨询:点击这里给我发消息

微信号:itpux-com

工作日:9:30-18:30,节假日休息