【问题标题】:How to Compare Huge Array to Database (with PHP or SQL)如何将庞大的数组与数据库进行比较(使用 PHP 或 SQL)
【发布时间】:2014-12-26 13:28:40
【问题描述】:

我有一个大的二维数组(576,000 X 4)和巨大的数据库(数百万条记录和 10 列,其大小以千兆字节为单位)。当然,数组比数据库中的记录数要小得多。

我需要一些有效的方法来将二维数组与数据库进行比较,并仅从二维数组中删除相等的线。

有谁知道我怎样才能有效地应用它?速度对我来说非常重要。


我试着这样应用它:

$query = mysqli_query($config, "SELECT * FROM sec ") or die(mysql_error());
while ($row = mysqli_fetch_array($query) ) {
    if ( isset($arr[$row['CHROM']][$row['POS']]) ) {
        // delete line from the 2D array
    }
}

但是,我不知道它的效率如何,因为我只是在小型数据库上尝试过,它使我将数据库的所有记录加载到 PHP 页面中,并且会产生内存问题。

我检查的另一种方法是:

foreach ($arr as $chr=>$v) {
    foreach ($v as $pos=>$val) {
        $query = mysqli_query($config, "SELECT * FROM sec WHERE CHROM='$chr' && POS='$pos' ") or die(mysql_error());
        if (mysqli_num_rows($query) > 0) {
            // delete line from the 2D array
        }
    }
}

但是,这不是一个好的解决方案,因为它花费了太多时间。


编辑:

我的sec 表是这样的:

对二维数组中的项目的调用看起来像 $arr[some_CHAROM][some_POS]

如果some_CHAROM 等于数据库中的某个CHAROM AND some_POS 等于同一行中的POS,我们就有一个匹配项。


我从用户上传到网站的文件构建二维数组。而且我没有将它加载到 mySql。

【问题讨论】:

  • 我认为 T-SQL 和 MySQL 是互斥的。
  • 你不能用 tsql 和 MySQL 数据库,你的意思是你有一个 MSSQL(例如 SQL Server)数据库?
  • 澄清一下,您正在尝试将大型数据库中的记录与二维数组中的记录进行比较,对吧?
  • @GolezTrol 很高兴知道这一点。我试图从谷歌那里得到一些想法,而 t-sql 是我在那里看到的东西之一,我一直在想这可能会起作用。
  • 你的大阵列从何而来?如果这也来自数据库,那么直接在那里进行比较可能更容易

标签: php mysql sql


【解决方案1】:

算法:

  1. 将用户上传的文件转换成CSV文件(如果还没有这种格式);这是一个简单的任务,可以用几行 PHP 代码完成;见函数fputcsv()
  2. 创建缓冲表:tbl1;
  3. 使用LOAD DATA LOCAL INFILE将(本地)CSV文件的内容加载到缓冲表tbl1中;
  4. 使用:

    DELETE tbl1
    FROM tbl1
        INNER JOIN tbl2 on tbl1.id = tbl2.id
    

    从表tbl1 中删除与表tbl2 匹配的行。我假设两个表上的匹配字段都命名为id;更改它以匹配您的设计;

  5. 从表tbl1中获取数据,按照你的意愿格式化,发送到浏览器;
  6. 清理:DROP TABLE tbl1;

因为脚本处理用户上传的文件,为了避免任何并发问题,您需要为缓冲区表生成每个用户的唯一名称。您可以使用前缀并将 userId 附加到它,以避免两个用户同时使用同一个表。

【讨论】:

  • 在 tbl1.id 上建立一个索引可能是值得的(假设 tb2.id 上已经有一个!)+1
  • tbl2.id 上的索引需要帮助查询尽可能快地运行。 tbl1.id 上的索引并不是真正需要的,但如果 tbl1 有很多列,它确实会有所帮助。因为没有WHERE子句,所以分析JOIN左侧表的所有行。 MySQL 的查询计划器在分析查询时会将左侧行数较少的表放在左侧(tbl1 此处的行数较少)。 tbl1.id 上的索引确实有帮助;它允许 MySQL 从索引中读取 tbl1.id 的值,而不是读取表数据 -> 从存储中加载的字节更少 -> 执行速度更快。
【解决方案2】:

试试下面的代码

$servername = "localhost";
$username = "root";
$password = "";
$dbname = "drupal7";


mysql_connect($servername, $username, $password );
mysql_select_db($dbname);




$sql = "SHOW TABLES FROM $dbname";
$result = mysql_query($sql);

if (!$result) {
    echo "DB Error, could not list tables\n";
    echo 'MySQL Error: ' . mysql_error();
    exit;
}
$database1=array();
while ($row = mysql_fetch_row($result)) {

    $result1 = mysql_query("SELECT * FROM ".$row[0]);
    if(mysql_num_rows($result1)){
        $num_rows = mysql_num_rows($result1);
    // echo "Table: {$row[0]} ==>".$num_rows."<br>";
        $database1[$row[0]]=$num_rows;
    }

    // }
}
echo '<pre>';
print_r($database1);

mysql_free_result($result);
// mysql_close();

$dbname='drupal71';
mysql_select_db($dbname);


$sql = "SHOW TABLES FROM $dbname";
$result = mysql_query($sql);

if (!$result) {
    echo "DB Error, could not list tables\n";
    echo 'MySQL Error: ' . mysql_error();
    exit;
}
$database2=array();
while ($row = mysql_fetch_row($result)) {

    $result1 = mysql_query("SELECT * FROM ".$row[0]);
    if(mysql_num_rows($result1)){
        $num_rows = mysql_num_rows($result1);
    // echo "Table: {$row[0]} ==>".$num_rows."<br>";
        $database2[$row[0]]=$num_rows;
    }

    // }
}


print_r($database2);


$test = array_diff($database1, $database2);

print_r($test);die;

【讨论】:

    【解决方案3】:

    从你的代码 sn-p

    foreach ($arr as $chr=>$v) {
        foreach ($v as $pos=>$val) {
            $query = mysqli_query($config, "SELECT * FROM sec WHERE CHROM='$chr' && POS='$pos' ") or die(mysql_error());
            if (mysqli_num_rows($query) > 0) {
                // delete line from the 2D array
            }
        }
    }
    

    我假设,您想根据$chr$pos 删除。

    因此,您可以执行以下操作:组装单个查询以将它们全部统治* :)

    $ors = array();
    foreach ($arr as $chr=>$v) {
        foreach ($v as $pos=>$val) {
            $ors[] = "CHROM='$chr' AND POS='$pos'";
        }
    }
    
    $deleteConditions = "(" . implode(") OR (", $ors) . ")":
    $query = mysqli_query($config, "DELETE FROM sec WHERE " . $deleteConditions);
    

    未经测试,但这应该会给你一个查询,比如

    DELETE FROM 
      sec 
    WHERE 
      (CHROM='1' AND POS='2') OR 
      (CHROM='3' AND POS='4') OR 
      (CHROM='5' AND POS='6') OR 
      ...
    

    取决于 $chr$pos 是什么。

    *正如 Ollie Jones 在 cmets 中指出的:注意整体查询长度。如果需要,创建第二个、第三个......查询,直到您处理了适当批次中的所有项目。

    【讨论】:

    • 如果你尝试这个,你会被max_allowed_packet 猛烈抨击。阅读:stackoverflow.com/questions/16335011/…
    • @OllieJones ofc。必须考虑这一点。但是要删除 10.000 行,最好批量删除,而不是触发单个查询。
    • 我没有从 mySql 中删除行,我只是从 2D 数组中删除行
    • @Idoroni,变化很大......(我留下答案,所以人们可以看到这个声明)对我来说,你的问题是“如何删除二维数组中的数据库行。 "
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多