2012-07-12 68 views
4

我在那里我存储唯一的文本字符串,然后我做选择如何检查是否在数据库中存在的记录 - 最快的方法

String checkIfAlreadyScanned = "SELECT id FROM \"STRINGS_DB\" where STR ='" + mystring + "'"; 

然后检查是否在数据库中存在该字符串表我是否值存在。我的数据库有大约5mil的记录;我可以改进我的方法吗?

也许有一种方式创建一个新的属性(hashedSTR)为例,并将字符串转换为一些独特的数字值,然后得到这些数字,而不是字符串?这会更快吗? (?将是在所有的工作)

+0

什么是数据库? – 2012-07-12 19:07:14

+5

除了在STR字段中加入索引外,没有太多可以做的事情。 – 2012-07-12 19:08:01

+0

出于好奇,查询字符串有什么问题..为什么有一个]“STRINGS_DB \” – MethodMan 2012-07-12 19:09:45

回答

4

保证了最快的处理,确保:

  • 您正在搜索的字段建立索引(您讲述一个“独一无二”的字符串,所以我假设它已经是这样了。因为这个原因,“限1”是没有必要的。否则,它应该被添加)
  • 您在使用Command对象的ExecuteScalar()方法
+0

+ ExecuteScalar()'建议 – 2012-07-12 19:23:10

1
String checkIfAlreadyScanned = "SELECT 1 FROM \"STRINGS_DB\" where STR ='" + mystring + "'"; 

如果您的结果集包含行,那么你就会有记录

+0

这将返回匹配条件的所有行,这些条件对性能不好 – 2012-07-12 19:17:07

1

限制结果设置为1:

String checkIfAlreadyScanned = @" 
    SELECT id 
    FROM ""STRINGS_DB"" 
    where STR ='" + mystring + @"' 
    limit 1"; 

这一个指数该专栏以及针对ExecuteScalar()的@Laurent建议将产生最佳结果。

此外,如果mystring有任何机会已被用户触及然后参数化查询,以避免SQL注入。

一个清洁的版本:

String checkIfAlreadyScanned = @" 
    SELECT id 
    FROM ""STRINGS_DB"" 
    where STR = '@mystring' 
    limit 1 
    ".replace("@mystring", mystring); 
+0

问题中的第一句:“唯一文本字符串”。没有倍数。 – 2012-07-12 19:47:58

0

[编辑] 限制结果返回到返回它遇到的第一个记录符合标准: 使用Sql Server:选择TOP 1 ...; 对于mysql/postgres:select ... LIMIT 1;

如果可以有多个,那么在您的select语句中添加“TOP 1”可能会返回得更快。

String checkIfAlreadyScanned = "SELECT TOP 1 id FROM \"STRINGS_DB\" where STR ='" + mystring + "'"; 

这样,它只需要找到字符串的第一个实例。

但是,如果您没有倍数,那么使用这种方法不会看到太多好处。

就像其他人所说的那样,在它上面加上索引可能会有所帮助。

+0

-1在postgresql中没有'TOP' – 2012-07-12 19:21:40

+0

如果您使用的是postgres,只需在末尾添加“limit 1”:http://forums.devshed.com/postgresql-help-21/how-to-take-top- 5-records-using-select-in-postgres-92744.html – Brandon 2012-07-12 19:25:53

+0

问题中的第一句话:“独特的文本字符串”。没有倍数。 – 2012-07-12 19:44:44

0

假设你实际上并不需要的id列,我认为这使编译器有机会最优化:

select 1 
where exists(
    select 1 
    from STRINGS_DB 
    where STR = 'MyString' 
) 
+0

'EXISTS'半联接可以帮助重复,但不会与“唯一的文本字符串”。 – 2012-07-12 19:46:16

1

多久这些文本字符串?如果它们很长,可以通过存储字符串的散列(以及原始字符串)来提高性能。

CREATE TABLE strings_db (
    id  PRIMARY KEY INT, 
    text  TEXT, 
    hash  TEXT 
); 

您的哈希列可以存储MD5总和,CRC32s或您选择的任何其他哈希算法。它应该被索引。

然后修改您的查询是这样的:

SELECT id FROM strings_db WHERE hash=calculate_hash(?) 

如果你的文本字段的平均大小是比你的哈希的尺寸足够大,这样做在较短场搜索将磁盘I帮助/ O.这也意味着在插入和选择时计算散列以及用于存储散列的额外磁盘空间会产生额外的CPU开销。所以所有这些因素都必须考虑在内。

P.S.始终使用预准备语句来避免SQL注入攻击!

+0

这不是索引工作吗? – 2012-07-12 19:25:58

+0

@Clodoaldo:PostgreSQL B树索引不这样做(我不知道任何无损索引引擎,但可能会有一些)。如果磁盘I/O是即时的,那么我的方法对于psql的默认B-Tree没有什么好处,因为必须在B-tree中遍历相同数量的索引记录,但是B树中的每个节点都包含较少数据,从磁盘读取数据会更快。我的磁盘I/O是免费的,这种方法没有任何优势。 – Flimzy 2012-07-12 19:37:49

0

虽然这里所有的答案都有其优点,但我想提一下另一个方面。

以这种方式构建您的查询并传递字符串不会帮助数据库引擎优化您的查询。相反,您应该编写一个存储过程,将其称为传递一个参数,并让数据库引擎构建一个查询计划并重用您的命令。

当然领域应该被索引

1

其实就是就是这样的东西你喜欢的。但它有一些限制。 PostgreSQL支持一个hash索引类型:

CREATE INDEX strings_hash_idx ON "STRINGS_DB" USING hash (str); 

作品进行简单的等式搜索与=,就像你拥有了它。我quote the manual的限制:

散列索引操作目前未WAL-记录,所以哈希索引 可能需要一个数据库崩溃后要与REINDEX重建。它们是 也不通过流式传输或基于文件的复制进行复制。对于 这些原因,目前不推荐使用散列索引。


一个真正的生命表,433K行,59 MB总简单的测试:

SELECT * FROM tbl WHERE email = '[email protected]' 
-- No index, sequnence scan: Total runtime: 188 ms 
-- B-tree index (default): Total runtime: 0.046 ms 
-- Hash index:    Total runtime: 0.032 ms 

这不是巨大的,但一些。与我测试中的电子邮件地址相比,差异将更大,更长的字符串。索引创建是1秒或2秒。与任一索引。

2

测试是没有意义的,只是包括在where子句中的“测试”:

INSERT INTO silly_table(the_text) 
'literal_text' 
WHERE NOT EXISTS (
    SELECT * 
    FROM silly_table 
    WHERE the_text = 'literal_text' 
    ); 

现在,你让测试仅在需要时:在语句的结束行将存在。有没有这样的事情尝试

对于那些不了解测试是没有意义的:测试意义,如果试验后的情况就不会被允许在测试后改变。这将需要测试&锁定方案。或者更糟的是:在交易中进行测试。

更新:版本作品(基本一致):

DROP TABLE exitsnot CASCADE; 
CREATE TABLE exitsnot 
     (id SERIAL NOT NULL PRIMARY KEY 
     , val INTEGER -- REFERENCES something 
     , str varchar -- REFERENCES something 
     ); 

INSERT INTO exitsnot (val) 
SELECT 42 
WHERE NOT EXISTS (
     SELECT * FROM exitsnot 
     WHERE val = 42 
     ); 
INSERT INTO exitsnot (str) 
SELECT 'silly text' 
WHERE NOT EXISTS (
     SELECT * FROM exitsnot 
     WHERE str = 'silly text' 
     ); 
SELECT version(); 

输出:

DROP TABLE 
NOTICE: CREATE TABLE will create implicit sequence "exitsnot_id_seq" for serial column "exitsnot.id" 
NOTICE: CREATE TABLE/PRIMARY KEY will create implicit index "exitsnot_pkey" for table "exitsnot" 
CREATE TABLE 
INSERT 0 1 
INSERT 0 1 
              version            
---------------------------------------------------------------------------------------------- 
PostgreSQL 9.1.2 on i686-pc-linux-gnu, compiled by gcc (Ubuntu 4.4.3-4ubuntu5) 4.4.3, 32-bit 
(1 row) 
+0

好点,至今错过了。 – 2012-07-12 23:19:26

+0

我刚刚添加了一些文字,因为我有时似乎有点神秘。整个话题是一个DBA与应用程序员之间的事情。 (你可能知道这个结果;-)顺便说一句:这是1/2的速度改进,因为测试将与I/U/D一样昂贵。 – wildplasser 2012-07-12 23:23:10

+0

你确定这是正确的语法吗?我的postgre在'where'显示错误' – Andrew 2012-07-13 00:42:07

相关问题