【问题标题】:How to convert about 16 million rows in mysql with least time?如何用最少的时间在 mysql 中转换大约 1600 万行?
【发布时间】:2015-03-31 07:24:31
【问题描述】:

我在一个只有两列的表中有大约 160 万行,一个是 bigint 唯一索引,另一个是 longblob,在 base64 中有照片。我需要尽快解码这些 base64 照片。我尝试使用几个小时后中断的java程序,速度也不好。这是程序

Connection conn = null;
        Statement stmt = null;
        try {
            conn = DatabaseConnection.getConnection();
            stmt = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,
                    ResultSet.CONCUR_UPDATABLE);
            ResultSet uprs = stmt.executeQuery("SELECT uniqueid,photo FROM newphotodata");
            String query="insert into photo_data values (?,?)";
            PreparedStatement pstmt =  conn.prepareStatement(query);
            while (uprs.next()) {
                byte[] processed = Base64Utils.base64Decode(uprs.getString(2));
                pstmt.setString(1, uprs.getString(1));
                pstmt.setBytes(2, processed);
                pstmt.executeUpdate();
                uprs.deleteRow();
            }
            pstmt.close();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            try {
                if (stmt != null)
                    stmt.close();
                if(conn!=null)
                    conn.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

我采用的第二种方法是使用数据库触发器,它使用我创建的 base64_decode 存储过程。这是触发器

DELIMITER $$

DROP TRIGGER `delete_photo`$$

CREATE TRIGGER `delete_photo` BEFORE DELETE ON `newphotodata`
FOR EACH ROW
BEGIN
    INSERT INTO `photo_data` SELECT OLD.`uniqueid`, BASE64_DECODE(OLD.`photo`);
END$$

DELIMITER ;

处理速度又太慢了。是否有任何其他方法可用于执行以下任务。我在 Redhat Linux 上运行 Mysql 5.0 版,96GB RAM,intel Xeon x5672。

【问题讨论】:

    标签: java mysql sql linux stored-procedures


    【解决方案1】:

    最好的方法是创建另一个表并使用预构建的mysql函数插入解码后的照片,以在base64上解码encode。

    插入比更新快。

    INSERT INTO photo_data 
    SELECT OLD.uniqueid, FROM_BASE64(OLD.`photo`);
    

    但如果您不每隔几行提交一次,此查询可能会变得很长。 所以最好的方法是创建一个每 n 行提交一次的过程。

    不要退出 mysql 以获得最佳性能。在 mysql 之外进行的每个转换都需要额外的努力。

    已编辑:按 uniqueId 对原始数据进行排序。如果发生问题,您可以从最后插入的 id 重新启动。您不需要删除原始数据。它可以提高你的表现。

    【讨论】:

    • 我正在以 100 行批次在另一个表中进行插入,并删除旧表中的现有行以避免出现问题时造成混乱。但是我认为使用我自己的存储过程进行解码需要很长时间,并且 mysql 5.0 中不存在内置的 int mysql 函数
    • 发布您的 base64 函数,以便我们查看是否有可能增强它们。此外,我通过其他增强功能编辑了我的答案。
    【解决方案2】:

    对于 java 程序,您可以尝试使用 sql 批处理语句,这将大大提高插入语句的速度。示例代码:

    int batchLimit = 1000;
    int currentBatchLimit = batchLimit;
    while (rs.next())
    {
        stmt.setInt(1, 123);
        stmt.addBatch();
    
        currentBatchLimit--;
        if (currentBatchLimit == 0)
        {
            stmt.executeBatch();
            stmt.clearBatch();
            currentBatchLimit = batchLimit;
        }
        stmt.clearParameters();
    }
    stmt.executeBatch();
    stmt.close();
    

    【讨论】:

    • 好的,如果我通过在同一个表上转换来更新行并且程序崩溃,那么我将如何区分哪些行已被转换或哪些未转换?
    • 您不需要在同一张表上更新它们。我认为最好使用 Davide Lorenzo MARINO 的方法以获得最佳性能。
    猜你喜欢
    • 2021-11-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-31
    相关资源
    最近更新 更多