C# 如何检查数据库中是否存在记录-最快方法
我有一个存储唯一文本字符串的表,然后通过执行select检查数据库中是否存在该字符串C# 如何检查数据库中是否存在记录-最快方法,c#,database,string,performance,postgresql,C#,Database,String,Performance,Postgresql,我有一个存储唯一文本字符串的表,然后通过执行select检查数据库中是否存在该字符串 String checkIfAlreadyScanned = "SELECT id FROM \"STRINGS_DB\" where STR ='" + mystring + "'"; 然后我检查值是否存在。我的数据库有大约5英里的记录;我可以改进我的方法吗 例如,也许有一种方法可以创建一个新属性(hashedSTR),将字符串转换成一些唯一的数字值,然后得到这些数字,而不是字符串?那会更快吗?(这行得通
String checkIfAlreadyScanned = "SELECT id FROM \"STRINGS_DB\" where STR ='" + mystring + "'";
然后我检查值是否存在。我的数据库有大约5英里的记录;我可以改进我的方法吗
例如,也许有一种方法可以创建一个新属性(hashedSTR),将字符串转换成一些唯一的数字值,然后得到这些数字,而不是字符串?那会更快吗?(这行得通吗?)
如果结果集包含一行,则您有一条记录将结果集限制为1:
String checkIfAlreadyScanned = @"
SELECT id
FROM ""STRINGS_DB""
where STR ='" + mystring + @"'
limit 1";
这、该列上的索引以及@Laurent对ExecuteScalar()
的建议将产生最佳结果
另外,如果mystring
有可能被用户触碰,则将查询参数化以避免sql注入
更简洁的版本:
String checkIfAlreadyScanned = @"
SELECT id
FROM ""STRINGS_DB""
where STR = '@mystring'
limit 1
".replace("@mystring", mystring);
[编辑]
限制返回的结果以返回它遇到的符合条件的第一条记录:
对于SqlServer:选择Top1。。。;
对于mysql/postgres:选择。。。限值1
如果可以有倍数,那么在select语句中添加“TOP 1”可能会更快返回
String checkIfAlreadyScanned = "SELECT TOP 1 id FROM \"STRINGS_DB\" where STR ='" + mystring + "'";
这样,它只需找到字符串的第一个实例
但是,如果没有倍数,那么这种方法可能不会带来太多好处
正如其他人所说,在其上添加索引可能会有所帮助。假设您实际上不需要
id
列,我认为这将为编译器提供最大的优化机会:
select 1
where exists(
select 1
from STRINGS_DB
where STR = 'MyString'
)
这些文本字符串有多长?如果字符串很长,您可以通过存储字符串的散列(以及原始字符串)来提高性能 您的哈希列可以存储MD5和、CRC32或您选择的任何其他哈希算法。它应该被编入索引 然后将查询修改为类似以下内容:
SELECT id FROM strings_db WHERE hash=calculate_hash(?)
如果文本字段的平均大小远远大于散列的大小,则在较短的字段上进行搜索将有助于磁盘I/O。这也意味着在插入和选择计算散列时会增加CPU开销,并增加存储散列的磁盘空间。因此,必须考虑所有这些因素
注意:始终使用准备好的语句来避免SQL注入攻击 虽然这里所有的答案都有其优点,但我想提到另一个方面 以这种方式构建查询并传递字符串无助于数据库引擎优化查询。相反,您应该编写一个存储过程,通过单个参数调用它,让数据库引擎构建一个查询计划并重用您的命令
当然,该字段应编入索引为确保处理速度最快,请确保:
- 您正在搜索的字段已编入索引(您说过有一个“唯一”字符串,因此我认为它已经存在。因此,不需要“限制1”。否则,应添加它)
- 您正在使用命令对象的
方法ExecuteScalar()
哈希
索引类型:
CREATE INDEX strings_hash_idx ON "STRINGS_DB" USING hash (str);
适用于使用=
进行简单的相等搜索,就像您拥有它一样。一、关于限制:
哈希索引操作目前未记录,因此哈希索引
数据库崩溃后,可能需要使用REINDEX重建。他们是
也不能通过流式或基于文件的复制进行复制。对于
由于这些原因,目前不鼓励使用散列索引
在现实生活中的表上进行快速测试,433k行,总计59MB:
从tbl中选择*其中email='some。user@some.domain.com'
--无索引,顺序扫描:总运行时间:188毫秒
--B树索引(默认):总运行时间:0.046毫秒
--哈希索引:总运行时间:0.032毫秒
这不是很大,但有点大。与我测试中的电子邮件地址相比,字符串较长的差异将更大。创建索引只需1或2秒。使用任一索引。测试没有意义,只需在where子句中包含“测试”:
INSERT INTO silly_table(the_text)
'literal_text'
WHERE NOT EXISTS (
SELECT *
FROM silly_table
WHERE the_text = 'literal_text'
);
现在,您将仅在需要时进行测试:在语句末尾,该行将存在。没有“尝试”这回事
对于那些不了解测试的人来说,测试毫无意义:如果测试后的情况不允许在测试后发生变化,那么测试就有意义。这需要一个测试和锁定场景。或者,更糟糕的是:事务内部的测试
更新:有效版本(基本相同):
输出:
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)
除了在STR字段上添加索引之外,您没有什么可以做的。出于好奇,查询字符串是怎么回事……为什么会有一个“]“STRINGS\u DB\”您也可能在那里进行sql注入,只是说。如果STRINGS表没有更新,那么打包页面(填充因子=100%)并将字符串作为主键(使用关联的唯一索引)是最快的方法。在某些数据库中,下面提到的exists()子句在这种情况下可能会稍微快一点。检查是无用的;下次尝试插入(或更新或删除)时,它可能已更改。(甚至)在传输中,您可以在(不)存在的位置添加
(…)
term到查询中。这将返回所有与不利于性能的条件匹配的行。如果使用postgres,请在末尾添加“限制1”:问题的第一句:“唯一文本字符串”。无倍数。@Clodoaldo:PostgreSQL B-Tree索引不执行此操作(据我所知,没有任何无损索引引擎能做到这一点,但可能有一些)。如果磁盘I/O是瞬时的,那么与psql的默认B-树相比,我的方法没有任何优势,因为B-树中必须遍历相同数量的索引记录,但是由于B-树中的每个节点包含的数据较少,从磁盘读取数据的速度更快。
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)