通过扩展字段来更新MySql表的有效方法

时间:2014-05-21 12:19:55

标签: mysql sql database relational-database mysql-python

我想扩展我的推文(Twitter)数据库。该数据库包含id INT,created_at DATETIME和json TEXT字段。我想按如下方式更新我的数据库。我想添加2个名为user_id的额外列和应从json部分提取的坐标。

我的想法是编写一个python脚本并逐行更新数据库。但是,这种方法听起来有点糟糕。这是因为对于每一行,我需要用python读取它,解析它然后更新表。有没有更聪明的方法使用MYSQL函数?

我的数据库有3个月的行,每天大约10000行,结果是1M行。

我有一个id的主索引和DATETIME的BTREE索引,该表在30个表中分区。

另外我注意到,当我逐个从python中插入数据库时​​,比加载csv文件所需的时间慢得多。这就是我想再次避免python的原因。

1 个答案:

答案 0 :(得分:1)

在存储过程中解析JSON没有优雅的方法。您可能会想出一些可以使用字符串函数提取所需项目的kludge。但这听起来很讨厌和不可靠。

创建元数据表

根据我的经验,处理这种扩展操作的一种好方法是添加一个新表而不是尝试将列添加到现有表中。

您的新表格,我们称之为metadata,会有以下列:

id          PK, also FK to tweet table.  NOT autoincrement.
created_at  copied over from tweet table.  
user_id     the value of the user_id you extract.
lat         FLOAT value for coordinate, NULL if no coordinate was available
lon         FLOAT value or NULL like LAT.

您可以按照分区推文表的方式对metadata表进行分区。这就是我在此设计中复制created_at字段的原因。

填充元数据表

然后你可以运行一个后台客户端程序(用python或任何适合你的语言)来填充这个表。它将读取tweets表中的行,然后在此处插入相应的行。您可能可以批量生成100行左右,并使其速度相当快。

如果我是你,我会使用这样的查询来检索要更新的每批推文。

SELECT tweet.id, tweet.created_at, tweet.json
  FROM tweet
  LEFT JOIN metadata ON tweet.id = metadata.id
 WHERE metadata.id IS NULL
 LIMIT 100

这将获取100行(确切地说,哪些行>正式无法预测,但没关系),metadata中已经没有相应的行。

然后,提取元数据并插入所需的行。请注意,在许多情况下,INSERT比UPDATE快得多。此外,您可以使用具有此模式的查询执行多行INSERT:

 INSERT INTO metadata (id, created_id, user_id, lat, long)  VALUES
 (?,?,?,?,?),
 (?,?,?,?,?),
 (?,?,?,?,?),
 (?,?,?,?,?),
 (?,?,?,?,?)

这种多行INSERT通过减少服务器往返来提高速度。

您可以简单地循环这些100行批处理,直到查询不再有行。这个程序可能会运行几个小时来处理你的megarow,但那没关系。使用这种批处理策略,您可以随时重新启动它,它将占用它停止的位置。

如果您愿意,您甚至可以让它在新推文到达时填充新的元数据。

请注意,它未设置为运行更新程序的多个实例。如果您愿意,您需要对交易做些什么。 IMO不值得这么麻烦。

使用元数据

当您需要使用元数据时,您可以使用以下查询:

 SELECT tweet.whatever, tweet.whatever, 
        metadata.user_id, metadata.lat, metadata.lon
   FROM tweet
   LEFT JOIN metadata ON tweet.id = metadata.id
  WHERE tweet.created_at > NOW() - INTERVAL 1 HOUR

请注意,我使用了LEFT JOIN而不是JOIN,因此即使填充元数据的作业尚未完成,您仍然可以从tweet获取行。

您还可以更改插入新推文的软件,以便正确插入元数据。