有效地找到表中不存在的第一个数字?

时间:2016-01-03 22:25:05

标签: php sql performance sqlite

我有一张约528829行的表,看起来像是

CREATE TABLE `ips` (
  `id` INTEGER PRIMARY KEY AUTOINCREMENT,
  `ip` INTEGER NOT NULL DEFAULT NULL,
  `scantime` INTEGER NULL DEFAULT NULL,
  `pingable` INTEGER NULL DEFAULT NULL
);

现在我需要找到ip中不存在的第一个数字,从0开始,一直到4294967295(又名0xFFFFFFFF),

目前我只是使用

function isScanned($ip){
    static $isScannedStm=false;
    static $boundip=0;
    if($isScannedStm===false){
    global $db;
    $isScannedStm=$db->prepare('SELECT 1 FROM `ips` WHERE `ip` = :ip LIMIT 1');
    $isScannedStm->bindParam(':ip',$boundip,PDO::PARAM_INT);
    return isScanned($ip);
    }
    $boundip=$ip;
    $isScannedStm->execute();
    //var_dump($isScannedStm->fetch(PDO::FETCH_NUM));
    return !!($isScannedStm->fetch(PDO::FETCH_NUM));
}
//~~~
    while(isScanned($i)){
        ++$i;
    }

..它有效,但有528829行,我的Intel Atom C2750 @ 2.4GHz需要1小时30分钟......我怎样才能更快地找到这个值?最好更快?

2 个答案:

答案 0 :(得分:2)

我只在MySQL中测试了这个,希望它也能用于SQLite

SELECT ips.ip+1 AS Missing 
FROM ips
LEFT JOIN ips AS next ON ips.ip+1 = next.ip
WHERE next.ip IS NULL 
ORDER BY ips.ip LIMIT 1;

Caspar和splattru的解决方案:https://stackoverflow.com/a/6464763/1078488

答案 1 :(得分:0)

你可以考虑进行一种"二元搜索"。从连续数字[1, 2, 3, ... (n/2)]

的前半部分开始

如果结果数不等于当前列表中连续值的数量,则可以拆分初始列表并重新运行相同的逻辑,直到达到第一个非连续的ID。

否则,如果计数匹配,则转到连续ID的另一半。

然后,您的查询需要包含WHERE...IN子句。

这对你不起作用,但是这可能会有所帮助:

// Populate current set of consecutive integers
$list = array_fill(0, $count/2);
$listQuery = implode(',', $list);

global $db;

$isScannedStm = $db->prepare('
    SELECT 1 FROM `ips` 
    WHERE `ip` IN ('.$listQuery.') 
    GROUP BY `ip` 
    ORDER BY `ip` ASC
');
$isScannedStm->execute()

// Check num results 
if (count($list) !== $isScannedStm->fetch(PDO::FETCH_NUM)) {
    // Split the initial list in half 
    // OR loop through results and find when the ids are not consecutive   
}

可能有一种更简单的方法,可以考虑查看this question