我是Python,Raspberry Pi和MySQL的新手,我希望你能帮助我。我试图在Python中编写一个可以每秒将数据插入MySQL表的脚本。我可以插入数据,但不像我想要的那样是周期性的,我已经尝试了很多,但我无法找到问题的解决方案。这是我的Python代码和插入MySQL表的数据:
#!/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)
+-----+------------+----------+------+
| 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秒吗?我究竟做错了什么? 对不起英语不好,提前谢谢!
答案 0 :(得分:2)
您正在每次迭代时建立与数据库服务器的新连接。这可能需要任意时间。在循环之外移动.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()
答案 1 :(得分:1)
当尝试插入新行时,不要使用事务,也许某些表被锁定。
答案 2 :(得分:1)
每次数据之间的间隔可能是1秒吗?
理论上,是的,但在实践中,有太多其他因素超出您的控制范围,更有可能妨碍您。其中一些包括但不限于:
这意味着即使您的系统在大多数时间处于空闲状态,time.sleep(1)
也不能保证始终在完全 1秒内休眠,即使这样做,系统也可能一直在做其他事情(例如更多的I / O),并且每次都需要不同的时间来执行相同的操作。
此外,不是每次在循环内创建 new 连接,都应该保持连接打开并节省开销。
我做错了什么?
我不认为你在这里做任何特别错误的事情。代码看起来没问题,除了,因为每次创建一个新连接的额外开销 - 你不应该。除此之外,这里的问题归结为你无法控制的因素。
话虽如此,你可以采取一些措施来提高你的机会。
除了避免在每次迭代时打开/关闭数据库连接的开销之外,还应检查用于表的存储引擎。例如,根据您的MySQL版本,默认值可能仍为MyISAM
,这需要 table 锁定才能写入。
相比之下,InnoDB
在写入表时只需要行锁定,如果其他人正在使用该表,这应该会改进。如果您发现未使用InnoDB
,请发出alter table ...
查询以更改存储引擎。
交易意味着将2个或更多查询的集分组为一个单元,但您提交的是个人查询。相反,您应该将MySQL配置为启用自动提交,以便在提交和执行查询后不必等待显式commit
请求,从而节省服务器和客户端之间的一些通信开销。 / p>
您可以为程序设置更高的优先级,以便调度程序在此处更有用。它也可能有助于为数据库服务/进程做同样的事情。
其他用户级别的任务也可以在必要时降低其优先级。
答案 3 :(得分:0)
尝试在while条件之前创建与db的连接以保持打开连接。
答案 4 :(得分:0)
我看到的问题是连接+插入需要时间,这会加起来,你的过程最终会落后。
我要做的是从数据加载中分离数据收集(确保您每秒读取一次温度)(如果需要,数据加载可能需要超过一秒钟,但您不会落后)。 / p>
所以,如果我是你,我会有两个独立的脚本并行运行,并通过一些简单,快速和可靠的机制进行通信。 Redis中的列表可能效果很好。您还可以使用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()
您可以在上面添加一些改进,例如重用数据库连接,确保如果出现数据库错误,使用namedtuple而不是数组用于数据点等,就不会丢失临时值。