【问题标题】:MySQL COMPRESS vs PHP gzcompressMySQL COMPRESS 与 PHP gzcompress
【发布时间】:2014-07-07 09:40:22
【问题描述】:

我正在开发一个 PHP 应用程序,其中需要将大量文本存储在 MySQL 数据库中。遇到过 PHP 的 gzcompress 和 MySQL 的 COMPRESS 函数作为减少存储数据大小的可能方法。

这两个函数之间有什么区别(如果有的话)?

(我目前的想法是gzcompress 似乎更灵活,因为它允许指定压缩级别,而COMPRESS 可能更易于实现和更好的解耦?性能也是一个重要的考虑因素。)

【问题讨论】:

    标签: php mysql performance compression


    【解决方案1】:

    这两种方法或多或少是一回事,实际上你可以混合使用它们:在 php 中压缩,在 MySQL 中解压缩,反之亦然。

    在 MySQL 中压缩:

    INSERT INTO table (data) VALUE(COMPRESS(data));
    

    在 PHP 中压缩:

    $compressed_data = "\x1f\x8b\x08\x00".gzcompress($uncompressed_data);
    

    在 MySQL 中解压:

    SELECT UNCOMPRESS(data) FROM table;
    

    在 PHP 中解压缩:

    $uncompressed_data = gzuncompress(substr($compressed_data, 4));
    

    另一个选项是use MySQL table compression。

    只需要配置,就透明了。

    【讨论】:

    • php中为什么要在gzcompress前面加上"\x1f\x8b\x08\x00"?
    • 它是一个gzip文件的头部。 MySQL 需要它,PHP 不需要。
    • Ryan 写道,第一个字节不是标头,而是未压缩数据的长度。这是一个巨大的差异
    • 在 MYSQL 中解压缩 php gzcompress : SELECT UNCOMPRESS(CONCAT('\x1f\x8b\x08\x00', data)) FROM table;
    【解决方案2】:

    这可能是一个老问题,但它作为 Google 搜索目标很重要。 MySQL 的 COMPRESS() 与 PHP 的 gzcompress() 的结果是相同的,除了 MySQL 在数据上放了一个 4 字节的标头,表示未压缩的数据长度。您可以轻松地忽略 MySQL 的 COMPRESS() 的前 4 个字节并将其提供给 gzuncompress() 并且它将起作用,但是您不能获取 PHP 的 gzcompress() 的结果并在其上使用 MySQL 的 UNCOMPRESS(),除非您特别注意添加那个 4 字节长度的标头,这当然需要已经有未压缩的数据...

    【讨论】:

      【解决方案3】:

      接受的答案没有使用正确的 4 字节标头。
      前 4 个字节是 LENGTH,而不是静态标头。
      我不知道使用错误长度的影响,但它可能不好,并且有可能在将来(如果不是现在)崩溃数据库或表内容

      POC 示例的正确答案: mysql的输出:

      mysql : "select hex(compress('1234512345'))"
      0A000000789C3334323631350411000AEB01FF
      

      php 等价物:

      【讨论】:

      • 我检查了 RFC:zlib.org/rfc-gzip.html,标题似乎是正确的:1F 8B 08 00 = ID1|ID2|CM |FLG。
      • @MathieuDeKermadec 我没有深入研究它,但 mysql 使用字节头中未压缩数据的长度。所以它不能是静态的,它会随着数据大小的变化而变化。这只是意味着 mysql 没有遵循 RFC 或者他们对其进行了扩展。
      • 注意:使用strlen in 而不是mb_strlen 来计算长度。否则,对于具有多字节字符的字符串,它将失败。有关完整示例,请参阅 stackoverflow.com/a/65981666/413531。
      【解决方案4】:

      它们都使用 zlib,因此压缩可能大致相同。测试一下看看。

      【讨论】:

        【解决方案5】:

        添加此答案以供参考,因为我需要使用 uncompress() 来解压缩数据,其中解压缩后的大小存储在 blob 的单独列中。

        根据前面的答案, uncompress() 期望压缩数据的前 4 个字节为长度,以小端格式存储。这可以使用 concat 预先添加,例如

        select uncompress(
            concat(
                char(size & 0x000000ff),
                char((size & 0x0000ff00) >> 8),
                char((size & 0x00ff0000) >> 16),
                char((size & 0xff000000) >> 24),
            compressed_data)) as decompressed
        from my_blobs;
        

        【讨论】:

          【解决方案6】:

          Johns answer 几乎是正确的。长度必须使用strlen 而不是mb_strlen 来计算,因为后者会将多字节字符识别为“1 个字符”,尽管它们跨越多个字节。下面以一个由 3 个字节组成的“▄”字符为例:

          
          $string="▄";
          $compressed = gzcompress($string, 6);
          
          echo "with strlen\n";
          $len  = strlen($string);
          $head = pack('V', $len);
          $base64 = base64_encode($head.$compressed);
          
          echo "Length of string: $len\n";
          echo $base64."\n";
          echo `mysql -e "SELECT UNCOMPRESS(FROM_BASE64('$base64'))" -u root -proot -h mysql`;
          
          
          echo "\n\nwith mb_strlen\n";
          $len  = mb_strlen($string);
          $head = pack('V', $len);
          $base64 = base64_encode($head.$compressed);
          
          echo "Length of string: $len\n";
          echo $base64."\n";
          echo `mysql -e "SELECT UNCOMPRESS(FROM_BASE64('$base64'))" -u root -proot -h mysql`;
          

          输出:

          with strlen
          Length of string: 3
          AwAAAHicezStBQAEWQH9
          UNCOMPRESS(FROM_BASE64('AwAAAHicezStBQAEWQH9'))
          ▄
          
          
          with mb_strlen
          Length of string: 1
          AQAAAHicezStBQAEWQH9
          UNCOMPRESS(FROM_BASE64('AQAAAHicezStBQAEWQH9'))
          NULL
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-07-03
            相关资源
            最近更新 更多