【问题标题】:Efficient way to update MySql table by expanding fields通过扩展字段来更新 MySql 表的有效方法
【发布时间】:2014-05-21 12:19:54
【问题描述】:

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

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

我的数据库有 3 个月的行,每天大约有 10000 行,因此有 100 万行。

我在 id 上有一个主索引,在 DATETIME 有一个 BTREE 索引,该表被划分为 30 个表。

我还注意到,当我从 python 逐一插入数据库时​​,比加载 csv 文件所需的时间慢得多。这就是为什么我想再次避免使用 python。

【问题讨论】:

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


    【解决方案1】:

    在存储过程中解析 JSON 没有优雅的方法。您可能会想出某种组合来使用字符串函数提取您需要的项目。但这听起来令人讨厌且不可靠。

    为元数据创建表

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

    您的新表,我们称之为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
    

    这将获取在 metadata 中没有对应行的 100 行(确切地说是哪些行>这在形式上是不可预测的,但没关系)。

    然后,提取元数据并插入您需要的行。请注意,在许多情况下,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 获取行。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-12-02
      • 1970-01-01
      • 1970-01-01
      • 2021-01-10
      • 2018-07-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多