【问题标题】:Unique Record Insertion Best Practice in SQL Server CE ApplicationSQL Server CE 应用程序中独特的记录插入最佳实践
【发布时间】:2013-09-04 21:27:08
【问题描述】:

数据库引擎应该完成所有工作,还是应该由客户端应用程序负责检查唯一性?

我正在用 C# 开发一个应用程序来扫描驱动器并将文件信息存储在 SQL Server CE 数据库中,我想知道哪种方法可以确保唯一条目是“最佳”的。到目前为止,我尝试了以下三种方法,并没有发现任何性能差异:

  1. 维护一个集合对象
  2. 检查数据库中是否存在
  3. 依赖于数据库中的唯一索引

我的三种方法的伪代码。实际代码将文件分解为多个部分,并使用多个表来存储路径、扩展名、卷/服务器和其他信息,以及索引记录以查找数据。

collectionObj //initialize with existing records from database
While (filesToAdd.Count > 0 )
{
    file = filesToAdd.Dequeue();
    If(!collectionObj.Contains( file.Name ))
    {
        Insert file.Name into database
        collectionObj.Add(file.Name)
      }
}  

我认为使用方法 1 在内存中搜索对象会更快,但由于 SQL Server CE 数据库也在内存中,所以我不太确定它的好处。

While (filesToAdd.Count > 0 )
{
    file = filesToAdd.Dequeue();

    if(  ( select count(*) from database where filename = file.Name) == 0 )  
    {
       Insert file.Name into database
    }
}

方法 2 不使用任何额外的对象/内存,但会大量查询数据库以查找重复项。使用 SQL Server CE 网络流量不是问题,但过多的查询会影响性能。

While (filesToAdd.Count > 0 )
{
        file = filesToAdd.Dequeue();
        try
       {
          Insert file.Name into database
       }catch(Duplicate index violation exception)
       {
          //do nothing 
       }
}

我倾向于方法 3,主要是因为它简化了代码,但它似乎懒得成为最佳实践。同样在重复插入时,数据库会抛出错误,程序也是如此。这似乎会影响性能。

鉴于所提供的信息,当您知道会有很多重复信息时,将大量信息添加到数据库中的“最佳”方式是什么?如果数据主要是唯一的或主要是重复的,答案会改变吗?如果您有更好的方法,那么我会很高兴听到它的想法。我的问题专门针对没有 SQL Server 全部功能的 SQL Server CE,请在提供建议时牢记这一点。

【问题讨论】:

  • 看起来每个人都一致同意在表上设置唯一约束是防止数据库中重复值的最佳方法。此外,在尝试插入/更新之前尝试过滤值甚至可能没有太多好处。 Gordon Linoff 很好深入的回答,但我选择 Gary Walker 是因为他的回答最实用。我想我现在的问题是如果我要在插入之前过滤值我应该使用方法 1 还是 2(更多的代码和内存使用与数据库开销)?

标签: c# .net sql tsql sql-server-ce


【解决方案1】:

答案是。 . .在数据库中进行。

唯一性要求是数据的要求。应该使用数据库来执行这些要求。

请记住,确保唯一条目需要对 insertupdate 进行测试。而且,您希望将唯一性作为数据完整性的一部分。因此,无论更新或插入是如何完成的(通过您的应用程序、手动、通过触发器或其他方式),您都希望检查发生。确保它始终完成的唯一方法是在数据库中进行检查。

这个论点超越了性能。但是,假设唯一索引适合内存,则数据库应该非常有效地进行性能检查。在某些情况下,性能非常重要,以至于会在应用程序中检查约束。这些将很少见。而且,我可能会质疑为什么要使用数据库来存储此类应用程序的数据。

【讨论】:

  • 在设计我的应用程序时,我没有考虑过更新,这是依赖约束的一个很好的论据。在每次更改数据之前检查唯一性需要更多的代码。程序外部发生的更新和插入对于 SQL Server 来说更受关注,但您的观点仍然有效。在这个程序中,我更看重数据完整性而不是性能,尽管速度仍然很重要。
【解决方案2】:

正确答案和往常一样,这取决于。让数据库这样做的“懒惰”解决方案最终是正确的答案。但是,如果您可以在客户端过滤掉重复项,并且过滤掉的时间和精力足以避免让数据库执行所有过滤,那么在客户端过滤是有意义的。您仍将在数据库上强制执行唯一性,但您可以通过过滤掉客户端上的一些或大部分重复项来减轻其处理的一些负担。如果我从实际的应用程序经验中知道这样做是值得的,我可能只会走这条路。

【讨论】:

  • 一种组合方式,我喜欢这种理想。使用 Method1 来维护您期望许多重复值的小值集合是有意义的。例如,在我的程序中,我可以使用 collectionObj 过滤掉扩展类型,但让表上的唯一约束来处理插入文件名和目录。我从 Method1 移动到 Method2 因为我的集合对象开始占用大量内存,因为我在近 20,000 个目录中索引 100,000 个文件。但是,我不知道搜索集合还是数据库更有效,因为它们都在内存中。
  • 我以为您提到了客户端上的过滤。如果是这样,过滤应该基本上是免费的(就数据库开销而言)。您可以让 Web 服务器(或任何中间层服务器)缓存发送到客户端的与大量重复项相关的数据。
【解决方案3】:

为什么懒惰的好方法是坏方法?

如果您打算使用数据库来存储数据并且您想确保没有重复的条目,那么当然应该对您的行使用 UNIQUE 约束。它不仅可以帮助您保持无重复的数据存储,还可以为您提供识别每一行的好方法。

如果有重复条目,数据库引擎会在插入数据库时​​注意到这一点,并抛出一个您可以轻松捕获的错误/异常。

【讨论】:

  • 我完全同意你的意见。它的代码更少,内存中没有集合对象,并且可以防止所有重复。但是,我担心数据库的性能会引发很多错误。假设我要插入 1000 条记录,而 990 条是重复的。生成所有这些异常似乎效率低下。如果我知道很多会重复,我不应该在将命令发送到数据库之前尝试过滤掉它们吗?也许由于 SQLCE 数据库是随程序加载到内存中的,因此性能损失不会像在与网络 SQL Server 通信的应用程序中那样明显。
【解决方案4】:

显然,您希望数据库处理唯一约束,但听起来您希望避免尝试插入重复记录时引发的异常。通常,我建议在您的 SQL INSERT 语句中使用 IF NOT EXISTS,但您不能使用 SQL Server Compact 执行此操作。

另一个技巧可能是先尝试更新,如果没有行受到影响,您就知道该记录不存在,您可以安全地插入它。这是一些额外的工作,但如果您预计会有很多重复,它可能仍然比捕获所有这些异常更有效。

在尝试将已知重复项放入数据库之前尝试过滤掉它们也可能是明智之举。也许考虑使用 HashSet 来跟踪您在该会话期间已插入的唯一 ID。如果一个值在您的 HashSet 中,您知道您可以跳过它并为自己保存对数据库的调用。

【讨论】:

  • 你说得对,我不喜欢故意引发异常的理想。当我意识到 IF NOT EXISTS 不起作用时,我使用了在程序中维护一组值的方法 1 来进行过滤。我的 collectionObj 是一个 HashTable,其中 key = item 和 value = SELECT @@IDENTITY 插入后。如果我只是存储会话的值,我仍然会得到数据库中已经存在的所有值的重复值。您建议测试 UPDATE 以检查现有值,并在 Method2 中使用 SELECT 来检查是否存在。在这种类型的任务中,UPDATE 是否比 SELECT 更有效?
  • 我提到 UPDATE 主要是因为我最近遇到了一些类似的情况,我需要更新现有记录,这样我的脑海中就会浮现出这种模式。但是阅读总是比阅读和写作都快,所以如果你不需要 UPDATE,SELECT 会更好。
猜你喜欢
  • 2018-01-30
  • 2020-02-11
  • 1970-01-01
  • 1970-01-01
  • 2015-11-03
  • 2013-01-24
  • 1970-01-01
  • 1970-01-01
  • 2012-06-06
相关资源
最近更新 更多