用于数据采集的SQLite与CSV

用于数据采集的SQLite与CSV,sqlite,csv,Sqlite,Csv,我正在设计一个测量仪器,软件是在定制的Linux嵌入式系统(Buildroot)上用C++/Qt5.12编写的。数据为时间序列,分为两类: 实际物理数据,1..3个字段,采样周期5分钟 内务管理参数(温度、fow率等),5..10个字段,采样周期1..10秒 到目前为止,我一直在使用CSV文件,它们完成了这项工作。尽管数据不相关且数据采集率低,但我正在研究SQLite,因为: 由于事务而降低了在崩溃时生成损坏文件的风险 从长远来看,更灵活地更改数据格式,例如添加列,对处理软件的影响更小 B

我正在设计一个测量仪器,软件是在定制的Linux嵌入式系统(Buildroot)上用C++/Qt5.12编写的。数据为时间序列,分为两类:

  • 实际物理数据,1..3个字段,采样周期5分钟
  • 内务管理参数(温度、fow率等),5..10个字段,采样周期1..10秒
到目前为止,我一直在使用CSV文件,它们完成了这项工作。尽管数据不相关且数据采集率低,但我正在研究SQLite,因为:

  • 由于事务而降低了在崩溃时生成损坏文件的风险
  • 从长远来看,更灵活地更改数据格式,例如添加列,对处理软件的影响更小
  • Buildroot支持SQLite
问题:

  • 在这种情况下,SQLite看起来比CSV更明智吗
  • 该工具将全天候运行数年,因此我想我必须将数据库分为多个部分(例如每月),以使文件保持合理的小规模并进行归档。我想知道这有多容易。它可以通过cron作业实现自动化吗
  • 谢谢

    在这种情况下,SQLite看起来比CSV更明智吗

    我建议是的。主要是因为你可能想对这些数据做点什么,而不是花余生去查看它们

    也许您需要某种聚合的统计数据(一个摘要、平均值、最大值、最小值,可能用于比较时段)。SQLite可以使这变得非常简单和高效

    该工具将全天候运行数年,因此我想我必须将数据库分为多个部分(例如每月),以使文件保持合理的小规模并进行归档。我想知道这有多容易。它可以通过cron作业实现自动化吗

    Cron无需,利用SQLite的强大功能,可以轻松触发

    下面是一个例子,展示了一些您可以做的事情

    由于您有两组不同的读数物理(表)内务管理(表)示例中每个读数都有一个表

    • 物理表中有1列用于读取时间戳,4列用于读取
    • 内务处理表有1列时间戳和10列读取列
    该示例自动生成数据只需加载一些数据即可显示结果。该示例有这样一个表,用于控制插入的数据量,它有一行和一个值(尽管它可能有更多行),并提取该值以确定添加了多少数据

    • 值为1000时,每5分钟将添加1000个物理读数(大约3.5天的数据)
    • 值为1000时,将向内务管理表中添加300000行。i、 e每5分钟将添加300行
    该示例演示了基于自动(触发器)的整理(不备份数据,但会从两个表中清除数据(只是一个显示可以自动执行操作的示例))。触发器名为“自动”tidyup

    要知道触发器正在被激活,它会另外记录触发器处理的开始和结束(激活时它会做什么以及它的when子句条件得到满足(以减少它尝试做某事的时间))。该数据存储在另一个表中,即tidyup\u log

    • 触发器已设置为触发WHEN子句(这将在测试到合适的时间表后更改)
    因此,在总结中有4个表(1个仅用于测试目的)和1个触发器

    加载数据后,数据将被3个查询用来提取有用的数据(well排序)

    示例SQL(请注意,可能最复杂的SQL用于加载测试数据):-

    删除表(如果存在);
    如果有,放下桌子;
    如果存在自动触发,则触发;
    如果存在tidyup_日志,则删除表;
    如果仅存在用于加载的\u,则删除表;
    如果不存在物理表(时间戳整数主键、fld1实数、fld2实数、fld3实数、fld4实数);
    如果不存在,则创建表(时间戳整数主键、prm1实、prm2实、prm3实、prm4实、prm5实、prm6实、prm7实、prm8实、prm9实、prm10实);
    如果不存在tidyup_日志,则创建表(时间戳整数,操作执行文本);
    如果不存在,则创建触发器在物理上插入后自动\u tidyup
    强制转换时(strftime(“%d”,“now”)为整数)=23/*>*/
    /*当强制转换时(strftime('%d','now')为整数=1*/*如果今天是月的第一天*/
    开始
    插入到tidyup_日志值中(strftime(“%s”、“now”)、“TIDY start”);
    从物理中删除,其中timestampDROP TABLE IF EXISTS physical;
    DROP TABLE IF EXISTS housekeeping;
    DROP TRIGGER IF EXISTS auto_tidyup;
    DROP TABLE IF EXISTS tidyup_log;
    DROP TABLE IF EXISTS just_for_load;
    CREATE TABLE IF NOT EXISTS physical(timestamp INTEGER PRIMARY KEY, fld1 REAL, fld2 REAL, fld3 REAL, fld4 REAL);
    CREATE TABLE IF NOT EXISTS housekeeping(timestamp INTEGER PRIMARY KEY, prm1 REAL, prm2 REAL, prm3 REAL, prm4 REAL, prm5 REAL, prm6 REAL, prm7 REAL, prm8 REAL, prm9 REAL, prm10 REAL);
    CREATE TABLE IF NOT EXISTS tidyup_log (timestamp INTEGER, action_performed TEXT);
    CREATE TRIGGER IF NOT EXISTS auto_tidyup AFTER INSERT ON physical 
        WHEN CAST(strftime('%d','now') AS INTEGER) = 23 /* <<<<<<<<<< TESTING SO GET HITS >>>>>>>>>>*/
        /*WHEN CAST(strftime('%d','now') AS INTEGER = 1 */ /* IF TODAY FIRST DAY OF MONTH */
        BEGIN
            INSERT INTO tidyup_log VALUES (strftime('%s','now'),'TIDY Started');
            DELETE FROM physical WHERE timestamp < new.timestamp - (60 * 60 * 24 * 365 /*approx a year */); 
            DELETE FROM housekeeping WHERE timestamp < new.timestamp - (60 * 60 * 24 * 365);
            INSERT INTO tidyup_log VALUES (strftime('%s','now'),'TIDY ENDED');
        END
    ;
    /* ONLY FOR LOADING Test Data controls number of rows added */
    CREATE TABLE IF NOT EXISTS just_for_load (base_count INTEGER);
    INSERT INTO just_for_load VALUES(1000); /* Number of physical rows to add 5 minutes e.g. 1000 is close to 3.5 days*/
    WITH RECURSIVE counter(i) AS 
        (SELECT 1 UNION ALL SELECT i+1 FROM counter WHERE i < (SELECT sum(base_count) FROM just_for_load))
        INSERT INTO physical SELECT strftime('%s','now','+'||(i * 5)||' minutes'), random(),random(),random(),random()FROM counter
    ;
    WITH RECURSIVE counter(i) AS 
        (SELECT 1 UNION ALL SELECT i+1 FROM counter WHERE i < (SELECT (sum(base_count) * 300) FROM just_for_load))
        INSERT INTO housekeeping SELECT strftime('%s','now','+'||(i)||' second'), random(),random(),random(),random(), random(),random(),random(),random(), random(),random()FROM counter
    ;
    
    /* <<<<<<<<<< DATA LOADED SO EXTRACT IT >>>>>>>>> */
    SELECT datetime(timestamp,'unixepoch'), fld1,fld2,fld3,fld4 FROM physical;
    /* First query to basically show the 5 minute intervals (and lots of random values)*/
    
    /* This query gets the sum and average of the 10 readings over a 5 minute window */
    SELECT 
        'From '||datetime(min(timestamp),'unixepoch')||' To '||datetime(max(timestamp),'unixepoch') AS Range,
            sum(prm1)AS avgP1, avg(prm1) AS sumP1,
            sum(prm2)AS avgP2, avg(prm2) AS sumP2,
            sum(prm3)AS avgP3, avg(prm3) AS sumP3,
            sum(prm4)AS avgP4, avg(prm4) AS sumP4,
            sum(prm5)AS avgP5, avg(prm5) AS sumP5,
            sum(prm6)AS avgP6, avg(prm6) AS sumP6,
            sum(prm7)AS avgP7, avg(prm7) AS sumP7,
            sum(prm8)AS avgP8, avg(prm8) AS sumP8,
            sum(prm9)AS avgP9, avg(prm9) AS sumP9,
            sum(prm10)AS avgP10, avg(prm10) AS sumP10
    FROM housekeeping GROUP BY timestamp / 300
    ;
    /* This query shows that the TRIGGER is being activated (even though it does no deletions) */
    SELECT * FROM tidyup_log;
    
    /* Tidy up the Testing environment */
    DROP TABLE IF EXISTS physical;
    DROP TABLE IF EXISTS housekeeping;
    DROP TRIGGER IF EXISTS auto_tidyup;
    DROP TABLE IF EXISTS tidyup_log;
    DROP TABLE IF EXISTS just_for_load;
    
    WITH RECURSIVE counter(i) AS 
        (SELECT 1 UNION ALL SELECT i+1 FROM counter WHERE i < (SELECT (sum(base_count) * 300) FROM just_for_load))
        INSERT INTO housekeeping SELECT strftime('%s','now','+'||(i)||' second'), random(),random(),random(),random(), random(),random(),random(),random(), random(),random()FROM counter
    > Affected rows: 300000
    > Time: 1.207s