上位机查询历史曲线慢,数据库层面优化
历史曲线是上位机最核心的功能,卡顿90%都是数据库没优化
1. 给时间字段建索引(最核心,必做)
你采集的温度、压力数据,全是按时间排序存储的 ,查询曲线时永远是 WHERE 采集时间 BETWEEN 开始时间 AND 结束时间
- 没索引:数据库要把几十万条数据从头到尾扫一遍(全表扫描),巨慢
- 建索引:数据库直接通过时间定位数据,10万条数据毫秒级查出
- 实操:给
CreateTime(采集时间)字段单独建索引,这是曲线查询提速的灵魂
2. 按天分表存储(海量数据必做)
如果你的设备常年采集,一张表存一年数据,会有几百万条记录,再快的索引也会卡
- 优化方案:每天生成一张新表,比如
Data_20260515、Data_20260516,查询哪个时间段,只查对应日期的表,数据量直接缩小几百倍
3. 只查询需要的字段,不要 SELECT *
很多人偷懒写 SELECT * FROM 数据表,会把所有字段(设备编号、备注、冗余字段)全部查出来
- 优化:只查曲线需要的
采集时间、压力值、温度值,减少网络传输和内存占用,速度直接翻倍
4. 开启SQLite的WAL预写日志模式(单机上位机专属)
你用SQLite做本地数据库时,默认模式下查询和写入不能同时进行,正在存实时数据时,查历史曲线就会卡顿
- 开启WAL后,实现读写分离,一边采集数据入库,一边查询曲线,互不阻塞,是工业单机上位机的标配优化
5. 强制限制查询时间范围
上位机前端加限制,比如最多只能查询7天内的数据,禁止用户查一年的历史曲线,从源头避免查询海量数据导致的卡顿
SQL注入风险
1. 什么是SQL注入?(举上位机真实例子)
核心:直接把用户输入的内容,拼接到SQL语句里执行,被恶意篡改SQL逻辑
举个你做报警查询的场景:
假设你写了这样一段拼接代码(错误写法):
csharp
// 用户在界面输入要查询的报警等级
string level = txt_Level.Text;
// 直接拼接SQL
string sql = "SELECT * FROM Alarm WHERE Level = '" + level + "'";
正常用户输入 1,SQL语句是:
SELECT * FROM Alarm WHERE Level = '1'(正常查询一级报警)
但如果有人故意在输入框里输入:' OR 1=1 --
拼接后的SQL变成:
SELECT * FROM Alarm WHERE Level = '' OR 1=1 --'
1=1永远成立,会查出整张表所有报警数据- 更恶劣的:输入
'; DROP TABLE Alarm; --,直接把你的报警数据表删掉,这就是SQL注入的危害
2. 上位机为什么要防注入?
- 工业场景:车间操作员、外部人员可能操作上位机,一旦注入成功,采集数据、报警记录全部丢失,甚至数据库被破坏
- 面试核心考点:面试官通过这个,判断你有没有工业软件安全意识
3. 上位机唯一正确的解决方法:参数化查询(绝对不要字符串拼接)
C#操作SQLite/MySQL,必须用参数化,示例:
csharp
// 正确写法,用占位符,系统自动转义特殊字符,杜绝注入
string sql = "SELECT * FROM Alarm WHERE Level = @Level";
SQLiteCommand cmd = new SQLiteCommand(sql, conn);
// 给占位符赋值,自动处理引号、特殊符号
cmd.Parameters.AddWithValue("@Level", txt_Level.Text);
原理:系统会把用户输入的内容只当成普通数据,绝对不会当成SQL语句执行,从根源彻底杜绝注入风险。