我们记录值,我们只在表中记录一次。当我们向表中添加值时,我们每次都要查看它是否需要插入值或只是获取id。我们在表上有一个索引(不在主键上),但是大约有350,000行(因此需要10秒才能完成10个这样的值)。
所以要么
答案 0 :(得分:2)
为了清楚起见,索引位于表中的(可能是varchar或nvarchar)字段,对吗?不是PK?
好的,编辑后:您正在对大(n)varchar文本字段进行索引查找。即使索引可能很慢 - 你仍然在进行2次大字符串比较。我真的不是一个很好的方法,但最初的SWAGS:
*是的,我知道我会为此降格,但有时候实用主义才有效。
答案 1 :(得分:1)
你多久写一次桌子而不是从桌子上读书。如果您经常写入和偶尔读取,请考虑始终执行插入操作,然后在执行选择时处理折叠值。
如果您尝试将所有内容放在一个表中,请考虑将它们分解为单独的表以减小大小,或禁止在表中使用分区。
答案 2 :(得分:1)
在350k行表上进行索引查找需要1秒钟?这对我来说听起来确实相当不必要。你确定没有其他错误吗?
答案 3 :(得分:1)
如果没有看到您的实际查询,我只能概括。但是,我会提供以下想法/建议:
1)您是否确认您的索引确实用于查询查询?如果它是一个具有高基数的索引,它应该更快。
2)您可以将2个操作组合到一个存储过程中,该存储过程首先查找该行,然后在必要时执行插入....类似于:
IF EXISTS (SELECT ID FROM YourTable WHERE ID = @ID_to_look_for) @ID_exists = 1 ELSE @ID_exists = 0
如果您发布确切查询的内容,也许我可以提供更详细的答案。
答案 4 :(得分:1)
不要进行查找,只需尝试插入值即可。如果该表被设计为拒绝重复记录,即它具有主键或唯一索引,那么插入将是错误的。只需捕获插入错误,如果收到,则按照通常的方式获取id。
我同意查找不应该花那么长时间,但为什么让引擎解析查询,映射路径,执行查找,然后在插入之前将结果发送给它,同时它可以同时执行这两个操作。
您还可以查看:
答案 5 :(得分:1)
首先,查看查询计划,看看它在做什么。这将告诉您它是否正在使用索引。单行测试/插入的一秒钟太慢。对于350k行,这足以让它在缓存表上进行表扫描。
二。查看服务器的物理布局。您是否有类似日志和数据共享同一磁盘的内容?
第三,检查唯一键上的索引列是否与select查询中的谓词的顺序相同。顺序差异可能会混淆查询优化器。
第四,考虑唯一键上的聚簇索引。如果这是查找行的主要模式,它将减少磁盘访问,因为表数据与聚簇索引物理存储在一起。有关聚簇索引的详细信息,请参阅This。用丰富的填充因子设置表格。
除非你有blob列,否则350k行远低于分区应该有所不同的阈值。此大小表应完全适合缓存。
答案 6 :(得分:0)
我不确定我是否有足够的信息来回答这个问题,但这里有一些想法:
答案 7 :(得分:0)
“当我们向表中添加值时,我们每次都要查看它是否需要插入值或只是获取id。”
我们习惯称之为“upsert”操作。
try:
UPDATE log SET blah blah blah WHERE key = key;
except Missing Key:
INSERT INTO log(...) VALUES(...);
我们从未做过自己的查询来查看密钥是否存在,因为这是UPDATE语句的作用。
答案 8 :(得分:0)
您是否偶然使用游标?它不应该在一张小桌子上花十秒钟来完成你说你做的事情。
您需要基于集合的更新和插入语句。
答案 9 :(得分:0)
排除连接和驱动程序问题 - 确保以相同方式执行的同一数据库上的其他操作足够快
确保您可以独立于可能在同一交易中运行的其他操作来衡量此操作
确保您没有锁定方案 - 停止其他所有操作,只需从管理工具执行查找和更新序列。
检查查找是否更昂贵(99%)或磁盘写入是否代价高昂 - 尽管即使对于慢速磁盘,10秒也太高了。这样做是为了完整。
检查查询是否正在使用您的索引 - 可能正在进行表扫描。
如果用于索引的列是文本字段,请通过在具有索引的非文本列上发出查找来检查文本索引是否位于问题的根源。如果是这样,尝试更改逻辑以使用PK或使用哈希而不是文本。