2011-05-11 55 views
4

我有可能会存储整数数十万的表:从一组值中,我如何找到未存储在表格列中的值?

desc id_key_table; 

+----------------+--------------+------+-----+---------+-------+ 
| Field   | Type   | Null | Key | Default | Extra | 
+----------------+--------------+------+-----+---------+-------+ 
| id_key   | int(16)  | NO | PRI | NULL |  | 
+----------------+--------------+------+-----+---------+-------+ 

从一个计划,我有一个大的整数集。我想看看哪些整数不在上面的id_key列中。

到目前为止,我想出了以下方法:

1)遍历每个整数,执行:

select count(*) count from id_key_table where id_key = :id_key 

当计数为0的id_key从表中缺少。

这似乎是一个可怕的,可怕的方式来做到这一点。


2)创建一个临时表,将每个值插入到临时表中,然后对这两个表执行JOIN。

create temporary table id_key_table_temp (id_key int(16) primary key); 

insert into id_key_table_temp values (1),(2),(3),...,(500),(501); 

select temp.id_key 
from id_key_table_temp temp left join id_key_table as main 
     on temp.id_key = main.id_key 
where main.killID is null; 

drop table id_key_table_temp; 

这似乎是最好的方法,但是,我敢肯定还有更好的方法,我还没有想到。我宁愿不必创建临时表并使用一个查询来确定哪些整数缺失。

是否有适合此类搜索的查询?

(MySQL的)

+0

第二种选择是最好的。 (检查速度的3种可能的写法查询方式,你编写的'LEFT JOIN - IS NULL','NOT IN'版本和'NOT EXISTS'方式。通常MySQL中的第一或第三更快。 – 2011-05-11 16:56:44

+0

我想你想检查的id_keys不是顺序的,(1-501)只是一个例子。 – 2011-05-11 16:58:13

+0

ypercube,正确,密钥不是顺序的。实际上可能有非常大的差距:例如100000 - 150000填充缺失的随机数,然后230000 - 400000填充缺失的随机数等。 – Clinton 2011-05-11 17:39:05

回答

4

在问题中给出的第二个例子中使用你的代码,我创建了两个存储过程(SP):1个SP加载素数作为密钥的样品台,其他SP找到缺少的整数。

这是第一个SP:

DELIMITER $$ 

DROP PROCEDURE IF EXISTS `test`.`CreateSampleTable` $$ 
CREATE PROCEDURE `test`.`CreateSampleTable` (maxinttoload INT) 
BEGIN 

    DECLARE X,OKTOUSE,MAXLOOP INT; 

    DROP TABLE IF EXISTS test.id_key_table; 
    CREATE TABLE test.id_key_table (id_key INT(16)) ENGINE=MyISAM; 

    SET X=2; 
    WHILE X <= maxinttoload DO 
    INSERT INTO test.id_key_table VALUES (X); 
    SET X = X + 1; 
    END WHILE; 
    ALTER TABLE test.id_key_table ADD PRIMARY KEY (id_key); 

    SET MAXLOOP = FLOOR(SQRT(maxinttoload)); 
    SET X = 2; 
    WHILE X <= MAXLOOP DO 
    DELETE FROM test.id_key_table WHERE MOD(id_key,X) = 0 AND id_key > X; 
    SELECT MIN(id_key) INTO OKTOUSE FROM test.id_key_table WHERE id_key > X; 
    SET X = OKTOUSE; 
    END WHILE; 
    OPTIMIZE TABLE test.id_key_table; 

    SELECT * FROM test.id_key_table; 

END $$ 

DELIMITER ; 

这里是第二个SP:

DELIMITER $$ 

DROP PROCEDURE IF EXISTS `test`.`GetMissingIntegers` $$ 
CREATE PROCEDURE `test`.`GetMissingIntegers` (maxinttoload INT) 
BEGIN 

    DECLARE X INT; 

    DROP TABLE IF EXISTS test.id_key_table_temp; 
    CREATE TEMPORARY TABLE test.id_key_table_temp (id_key INT(16)) ENGINE=MyISAM; 

    SET X=1; 
    WHILE X <= maxinttoload DO 
    INSERT INTO test.id_key_table_temp VALUES (X); 
    SET X = X + 1; 
    END WHILE; 
    ALTER TABLE test.id_key_table_temp ADD PRIMARY KEY (id_key); 

    SELECT temp.id_key FROM test.id_key_table_temp temp 
    LEFT JOIN test.id_key_table main USING (id_key) 
    WHERE main.id_key IS NULL; 

END $$ 

DELIMITER ; 

下面是使用25号创建素数第一SP的样品试验:

mysql> CALL test.CreateSampleTable(25); 
+-------------------+----------+----------+----------+ 
| Table    | Op  | Msg_type | Msg_text | 
+-------------------+----------+----------+----------+ 
| test.id_key_table | optimize | status | OK  | 
+-------------------+----------+----------+----------+ 
1 row in set (0.16 sec) 

+--------+ 
| id_key | 
+--------+ 
|  2 | 
|  3 | 
|  5 | 
|  7 | 
|  11 | 
|  13 | 
|  17 | 
|  19 | 
|  23 | 
+--------+ 
9 rows in set (0.17 sec) 

mysql> 

下面是使用25作为完整列表比较的第二个SP的运行:

mysql> CALL test.GetMissingIntegers(25); 
+--------+ 
| id_key | 
+--------+ 
|  1 | 
|  4 | 
|  6 | 
|  8 | 
|  9 | 
|  10 | 
|  12 | 
|  14 | 
|  15 | 
|  16 | 
|  18 | 
|  20 | 
|  21 | 
|  22 | 
|  24 | 
|  25 | 
+--------+ 
16 rows in set (0.03 sec) 

Query OK, 0 rows affected (0.05 sec) 

mysql> 

虽然这个解决方案对于小样本来说是可以的,但是大列表却成为一个令人头痛的问题。您可能想要保留临时表(不要一次又一次使用CREATE TEMPORARY TABLE,只使用CREATE TABLE一次),永久加载数字1 .. MAX(id_key)并通过id_key_table上的触发器填充该永久临时表。

只是一个问题,因为我很好奇:你是否这样做,看看是否可以重用表中的auto_increment键?

+0

“您是否正在执行此操作以查看表中的auto_increment键是否可以重用???”不,那是疯狂的谈话。我收到的数据集足以提供唯一的标识符,并且只是试图不重新处理已处理的数据。数据将倾向于从不同的来源重复出现(但仍提供相同的一致唯一标识符)。 – Clinton 2011-05-11 17:24:37

+0

@Clinton我见过其他开发者实际上在做这个疯狂的演讲,所以我听到你的声音。 – RolandoMySQLDBA 2011-05-11 17:28:14

+0

现在谁在点! +1好回答 – DTest 2011-05-11 18:27:16