MySQL到Redis在一个巨大的桌子上,如何加快速度


MySQL to Redis on a huge table, how to speed things up?

当我尝试将大量数据从 mysql 表获取到 redis 数据库时,我遇到了一点问题。无论如何,一段时间后我收到错误"MySQL服务器已消失",我不知道为什么。

编辑:

或者当我使用破坏循环的注释代码时,它只是在未完成时"完成"。

这是我使用的 php 代码(由 php-cli 运行):

<?php
require 'Predis/Autoloader.php';
Predis'Autoloader::register();
mysql_connect('localhost', 'root', 'notcorrect') or die(mysql_error());
mysql_select_db('database_that_i_use') or die(mysql_error());
$redis = new Predis'Client();
//starting on 0 but had to edit this when it crashed :(
for($i = 3410000; $i<999999999999; $i += 50000) {
        echo "Query from $i to  " . ($i + 50000) . ", please wait...'n";
        $query = mysql_unbuffered_query('SELECT * FROM table LIMIT ' . $i . ', 50000')or die(mysql_error());
        // This was code I used before, but for some reason it got valid when it wasn't supposed to. 
        /*if(mysql_num_rows($query) == 0) {
                echo "Script finished!'n";
                break;
        }*/
        while($r = mysql_fetch_assoc($query)) {
                $a = array('campaign_id' => $r['campaign_id'],
                           'criteria_id' => $r['criteria_id'],
                           'date_added' => $r['date_added'],
                );
                $redis->hmset($r['user_id'], $a);
                unset($a);
                usleep(10);
        }
        echo "Query completed for 50000 rows..'n";
        sleep(2);
}

unset($redis);
?>

的问题是如何做得更好,我真的不知道它为什么崩溃。我的服务器很旧,速度很慢,可能无法处理这么多数据?这只是我们切换到实际生产之前的测试服务器。

值得注意的是,脚本运行良好可能持续了半个小时,可能是限制语句在数字变高时使其非常慢?那么有没有更简单的方法可以做到这一点呢?我今天需要传输所有数据!:)

提前谢谢。

编辑:运行示例:

Query from 3410000 to  3460000, please wait...
Query completed for 50000 rows..
Query from 3460000 to  3510000, please wait...
Query completed for 50000 rows..
Query from 3510000 to  3560000, please wait...
Query completed for 50000 rows..
Query from 3560000 to  3610000, please wait...
MySQL server has gone away

编辑:

该表包含 ~500 万行数据,大小约为 800 MB。但是我以后需要为更大的表做类似的事情。

首先,您可能希望使用另一种脚本语言。Perl,Python,Ruby,任何东西都比PHP运行这种脚本更好。

我无法评论为什么 mysql 连接丢失,但为了获得更好的性能,您需要尝试使用 mysql 服务器和 redis 服务器尽可能多地消除往返。

这意味着:

  • 不应使用未缓冲的查询,而应使用缓冲的查询(前提是在查询中使用了 LIMIT)

  • 您不应该使用 LIMIT 迭代 mysql 查询,因为您会获得二次复杂度,而它应该只是线性的。我不知道是否可以在PHP中避免。

  • 您应该将发送到 Redis 的命令流水线化

下面是使用 Predis 进行流水线的示例:https://github.com/nrk/predis/blob/v0.7/examples/PipelineContext.php

实际上,如果我真的必须为此使用 PHP,我会将 mysql 数据导出到文本文件中(例如使用"select into outfile"),然后读取文件并使用流水线将数据推送到 Redis。