快速比较MySQL DB中的随机字符串

时间:2013-11-16 14:08:45

标签: php mysql database

我需要在数据库中存储1000个(可能很快就会有100,000个甚至数百万个)12个字符的独特随机字符串。每次我必须生成一个新代码(实际上是以10,000 + s批量完成)我需要将它与现有数据库进行比较以确保不会有重复 - 但是当代码被用户“兑换”时,我需要确保它存在。

这两项任务都可能非常缓慢,所以我希望尽可能简化它们。首先,我确保字符串以BINARY格式存储在DB上,并带有INDEX。这显然比CHAR,VARCHAR和VARBINARY更快。

我正在考虑尝试进一步改进,我提出了这个简单的想法:将第一个字符存储为索引列中的TINYINT,并首先进行比较 - 因此希望能够更快地找到匹配的记录。

例如:

public function getFirstCharAsNum($code) {
    $firstChar = substr($code, 0);
    $firstCharHex = bin2hex($firstChar);
    $prefix = hexdec($firstCharHex);
    return $prefix;
}

public function isDuplicate($generatedCode) {

    $result = false;

    $params["code"] = $generatedCode;
    $params["prefix"] = getFirstCharAsNum($generatedCode);

    $STH = $this->_db->prepare("SELECT count(*) FROM codes
        WHERE prefix = :prefix AND code = :code;");

    try {
        $result = $STH->execute($params);
    } catch (PDOException $e) {
        throw new Exception($e->getMessage());
    }   

    $result = $STH->fetch(PDO::FETCH_COLUMN);

    if($result) {
        return true;
    } else {
        return false;
    }        

}

这个想法是它只会在找到匹配项时尝试AND操作的第二部分,并且搜索TINYINTs应该比整个BINARY(12)列快得多。

这实际上更快吗?或者是添加额外的查找会让我慢下来?

感谢。

2 个答案:

答案 0 :(得分:1)

如果你这样做,那么代码生成将随着时间逐渐减慢,需要搜索更大的数据库,以及更大数据集上的更多冲突。

您可以使用预先生成的随机代码来准备表格。然后,记住Codes表中的偏移量。无论何时需要新代码,只需从代码表中获取 offset - 行并将 offset 增加1;这当然需要原子地完成,READ LOCK

独立的线程可以在适当的时候生成随机代码(例如,每当系统负载足够低;晚上;等等),并INSERT IGNORE将它们放入Codes表中:

CREATE TABLE Codes (
    offset   INTEGER PRIMARY KEY NOT NULL AUTO_INCREMENT,
    sequence BINARY(12)
);

要“生成”代码,您现在必须只执行一个在O(1)中执行的查询,因为它是一个固定地址的提取。如果将地址存储到代码偏移零中,可能会有两个查询:

LOCK TABLES test WRITE;
SELECT datum.sequence FROM Codes AS datum
    JOIN Codes AS ndx ON ( datum.offset = ndx.sequence AND ndx.offset = 0 );
UPDATE Codes SET sequence = sequence + 1 WHERE offset = 0;
UNLOCK TABLES;

插入新代码的线程会遇到减速,但不是很多(它还会在LOCK TABLES LOW PRIORITY WRITE s的每个块上使用INSERT。但是,所有需要 new 代码的流程都会非常快速。

当然,“补货”主题将从COUNT(*)表读取当前偏移量和Codes,如果有超过给定数量的代码,则拒绝运行。

检查和兑换

为此,我们可以添加一个“已兑换”的布尔列。要进一步提高速度,可以使用水平partitioning,将代码表划分为N个哈希分区。这样,不仅任何搜索都只能在一小部分数据上进行(不是比b树索引更好的改进......),但锁定和更新可以在表之间传播

您也可以“手动”并根据代码的第一个字母在不同服务器之间传播表格。这样,只要你提供足够的服务器,你就可以扩展到十亿个代码并且速度仍然很快。

答案 1 :(得分:1)

  

我需要在数据库中存储1000个(可能很快就会有100,000个甚至数百万个)12个字符的独特随机字符串

如果它们是真正随机的,则发生碰撞的可能性是{实际记录数} / {可能记录数}}

即使如果您从中选择的字符集包含数字,那么,有1000万条现有记录,发生碰撞的概率为10,000,000 / 1,000,000,000,000 = 1 / 100,000,因此,你所描述的实际上是浪费时间。在数据库中的值上添加唯一索引 - 如果您尝试添加新值时遇到唯一约束违规,则重新生成该值。

(有36个字符的曲目,碰撞的概率约为1 / 473,838,000,000)