每秒向MySQLtable插入数据(每秒一次)

Insert data to MySQL table every second (one time per second)

我是 Python、Raspberry Pi 和 MySQL 的新人,希望您能帮助我。我正在尝试在 Python 中编写一个脚本,它可以每秒将数据插入 MySQL table。我可以插入数据但不像我想要的那样定期插入,我已经尝试了很多但我找不到解决我的问题的方法。这是我的 Python 代码和插入到 MySQL table 中的数据:

Python代码:

#!/usr/bin/env python

import MySQLdb
import time

while True:
    db = MySQLdb.connect("localhost", "mauro", "12345", "temps")
    curs=db.cursor()
    try:
        curs.execute ("""INSERT INTO thetemps 
                values(0, CURRENT_DATE(), NOW(), 28)""")
        db.commit()
        print "Data committed"
    except:
        print "Error"
        db.rollback()
    db.close()
    time.sleep(1)

Table 结果:

+-----+------------+----------+------+
| id  | date       | time     | temp |
+-----+------------+----------+------+
| 107 | 2015-11-06 | 19:16:41 |   28 |
| 108 | 2015-11-06 | 19:16:42 |   28 |
| 109 | 2015-11-06 | 19:16:45 |   28 |
| 110 | 2015-11-06 | 19:16:46 |   28 |
| 111 | 2015-11-06 | 19:16:47 |   28 |
| 112 | 2015-11-06 | 19:16:48 |   28 |
| 113 | 2015-11-06 | 19:16:56 |   28 |
| 114 | 2015-11-06 | 19:17:00 |   28 |
| 115 | 2015-11-06 | 19:17:03 |   28 |
| 116 | 2015-11-06 | 19:17:05 |   28 |
| 117 | 2015-11-06 | 19:17:06 |   28 |
| 118 | 2015-11-06 | 19:17:07 |   28 |
| 119 | 2015-11-06 | 19:17:08 |   28 |
| 120 | 2015-11-06 | 19:17:09 |   28 |
| 121 | 2015-11-06 | 19:17:10 |   28 |
| 122 | 2015-11-06 | 19:17:11 |   28 |
+-----+------------+----------+------+

如您所见,有时脚本会定期插入数据,有时数据之间有 8 秒的间隔。所以,我的问题是:每次数据之间的间隔是否可以为1秒?我究竟做错了什么? 抱歉英语不好,提前致谢!

不要为此使用事务,可能一些 table 在尝试插入新行时被锁定。

您将在每次迭代中建立与数据库服务器的新连接。这可能需要任意时间。将 .connect() 等移动到循环之外可能会给您更一致的计时:

db = MySQLdb.connect("localhost", "mauro", "12345", "temps")
curs = db.cursor()

while True:    
    try:
        curs.execute ("""INSERT INTO thetemps 
                values(0, CURRENT_DATE(), NOW(), 28)""")
        db.commit()
        print "Data committed"
    except:
        print "Error"
        db.rollback()    
    time.sleep(1)
db.close()

尝试在 while 条件之前创建与数据库的连接以保持连接打开。

我看到的问题是连接+插入需要时间,这会加起来,你的过程最终会落后。

我要做的是将数据收集(确保您每秒读取一次温度)与数据加载分开(如果需要,数据加载可能需要一秒以上的时间,但您不会落后)。

所以,如果我是你,我会有两个并行的独立脚本 运行,并通过一些简单、快速和可靠的机制进行通信。 Redis would probably work great. You could also use something like ZMQ.

中的列表

像这样:

# gather.py
while True:
    temp = get_temp()
    redis.lpush('temps', pickle.dumps([temp, datetime.now]))
    time.sleep(1)

和..

# load.py
while True:
    # Block until new temps are available in redis
    data, key = redis.brpop('temps')
    # Get all temps queued
    datapoints = [data] +  redis.rpop('temps'):
    db = MySQLdb.connect("localhost", "mauro", "12345", "temps")
    curs=db.cursor()
    try:
        for p in datapoints:
            point = pickle.loads(p)
            curs.execute ("INSERT INTO thetemps (temp, timestamp) values({}, {})".format(point[0], point[1])
        db.commit()
        print "Data committed"
    except:
        print "Error"
        db.rollback()

您可以在上面添加一些改进,例如重用数据库连接,确保在出现数据库错误时不会丢失临时数据,使用命名元组而不是数据点数组等。

is possible to the interval between the data be 1 second every time?

理论上是的,但在实践中,有太多您无法控制的其他因素更有可能成为障碍。其中一些包括但不限于:

  1. OS 内核的任务调度器
  2. 相对于其他任务的优先级
  3. 整体系统负载
  4. table中已有的数据量(检查二叉树的时间复杂度)

这意味着即使您的系统大部分时间都处于空闲状态,time.sleep(1) 也不能保证总是休眠 正好 1 秒,即使它确实如此,系统可能一直在做其他事情(例如更多I/O)并且每次执行相同的操作需要不同的时间。

此外,与其在循环内每次都创建一个 new 连接,不如保持连接打开并节省开销。

What am i doing wrong?

我不认为你在这里做错了什么。代码看起来不错,除了每次创建新连接的额外开销——你不应该。除此之外,这里的问题归结为您无法控制的因素。

话虽这么说,但您可以采取一些措施来提高成功率。


一些提高性能的额外建议

存储引擎

除了避免每次迭代 opening/closing 数据库连接的开销外,您还应该检查用于 table 的存储引擎。例如,根据您的 MySQL 版本,默认值可能仍然是 MyISAM,这需要 table 锁定才能写入。

相比之下,InnoDB 在写入 table 时只需要 锁定,如果其他东西正在使用 [=82],这应该会有所改善=].如果您发现自己没有使用 InnoDB,请发出 alter table ... 查询以更改存储引擎。

自动提交而不是交易

事务旨在将 2 个或更多查询的 分组为一个单元,但您提交的是 单个 查询。相反,您应该配置 MySQL 以启用自动提交,这样它就不必在提交和执行查询后等待明确的 commit 请求,从而节省服务器和服务器之间的一些通信开销你的客户。

通过提高优先级来影响 OS 调度程序

您可以为您的程序设置更高的优先级,以便调度程序在这里更有帮助。它也可能有助于为数据库做同样的事情 service/process.

如有必要,其他用户级任务的优先级也可以降低一点。