使用Dapper删除超过2100行(通过ID)的正确方法

时间:2012-03-30 15:45:48

标签: sql-server parameters dapper

我正在尝试使用Dapper支持我的服务器应用程序的数据访问。

我的服务器应用程序有另一个应用程序,它以每分钟400的速度将记录删除到我的数据库中。

我的应用程序将它们分批拉出,处理它们,然后从数据库中删除它们。

由于数据在我处理过程中继续流入数据库,因此我无法说出delete from myTable where allProcessed = true

但是,我确实知道要删除的行的PK值。所以我想做一个delete from myTable where Id in @listToDelete

问题是,如果我的服务器连续下降了6分钟,那么我有超过2100行要删除。

由于Dapper接受我的@listToDelete并将每个变为参数,我对delete的调用失败。 (导致我的数据清除进一步落后。)

在Dapper处理这个问题的最佳方法是什么?

注意: 我查看了Tabled Valued Parameters,但从我所看到的情况来看,它们并不是performant。这段我的建筑是我系统的瓶颈,我需要非常非常快。

3 个答案:

答案 0 :(得分:14)

一种选择是在服务器上创建临时表,然后使用批量加载工具将所有ID一次上传到该表中。然后使用join,EXISTS或IN子句仅删除上传到临时表中的记录。

批量加载是SQL Server中经过充分优化的路径,它应该非常快。

例如:

  1. 执行语句CREATE TABLE #RowsToDelete(ID INT PRIMARY KEY)
  2. 使用批量加载将密钥插入#RowsToDelete
  3. 执行DELETE FROM myTable where Id IN (SELECT ID FROM #RowsToDelete)
  4. 执行DROP TABLE #RowsToDelte(如果您关闭会话,表格也将自动删除)
  5. (假设Dapper)代码示例:

    conn.Open();
    
    var columnName = "ID";
    
    conn.Execute(string.Format("CREATE TABLE #{0}s({0} INT PRIMARY KEY)", columnName));
    
    using (var bulkCopy = new SqlBulkCopy(conn))
    {
        bulkCopy.BatchSize = ids.Count;
        bulkCopy.DestinationTableName = string.Format("#{0}s", columnName);
    
        var table = new DataTable();                    
        table.Columns.Add(columnName, typeof (int));
        bulkCopy.ColumnMappings.Add(columnName, columnName);
    
        foreach (var id in ids)
        {
            table.Rows.Add(id);
        }
    
        bulkCopy.WriteToServer(table);
    }
    
    //or do other things with your table instead of deleting here
    conn.Execute(string.Format(@"DELETE FROM myTable where Id IN 
                                       (SELECT {0} FROM #{0}s", columnName));
    
    conn.Execute(string.Format("DROP TABLE #{0}s", columnName));
    

答案 1 :(得分:5)

为了让这段代码正常工作,我走到了黑暗的一边。

由于Dapper使我的列表成为参数。而SQL Server无法处理很多参数。 (我以前从未需要双位数参数)。我不得不使用Dynamic SQL。

所以这是我的解决方案:

string listOfIdsJoined = "("+String.Join(",", listOfIds.ToArray())+")";
connection.Execute("delete from myTable where Id in " + listOfIdsJoined);

在每个人抓住他们的火把和干草叉之前,让我解释一下。

  • 此代码在服务器上运行,该服务器的唯一输入是来自Mainframe系统的数据馈送。
  • 我动态创建的列表是longs / bigints列表。
  • longs / bigint来自Identity列。

我知道构建动态SQL是糟糕的juju,但在这种情况下,我只是看不出它会如何导致安全风险。

答案 2 :(得分:2)

Dapper请求具有参数的对象列表作为属性,因此在上面的情况下,具有Id作为属性的对象列表将起作用。

connection.Execute("delete from myTable where Id in (@Id)", listOfIds.AsEnumerable().Select(i=> new { Id = i }).ToList());

这样可行。