Sql server 使用Dapper删除2100多行(按ID)的正确方法

Sql server 使用Dapper删除2100多行(按ID)的正确方法,sql-server,parameters,dapper,Sql Server,Parameters,Dapper,我正在尝试为我的服务器应用程序使用“支持我的数据访问” 我的服务器应用程序有另一个应用程序,它以每分钟400次的速度将记录放入我的数据库 我的应用程序将它们分批提取、处理,然后从数据库中删除 由于数据在我处理时继续流入数据库,所以我没有一个好的方法说delete from myTable,其中allProcessed=true 但是,我知道要删除的行的PK值。所以我想从myTable中删除@listToDelete中的Id 问题是,若我的服务器宕机6分钟,那个么我有超过2100行要删除 由于Da

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

我的服务器应用程序有另一个应用程序,它以每分钟400次的速度将记录放入我的数据库

我的应用程序将它们分批提取、处理,然后从数据库中删除

由于数据在我处理时继续流入数据库,所以我没有一个好的方法说delete from myTable,其中allProcessed=true

但是,我知道要删除的行的PK值。所以我想从myTable中删除@listToDelete中的Id

问题是,若我的服务器宕机6分钟,那个么我有超过2100行要删除

由于Dapper接受了我的@listToDelete并将其转换为一个参数,因此我对delete的调用失败。使我的数据清理工作更加落后

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

注:
我已经看过表中的值参数,但从我所看到的,它们不是很重要。我的体系结构中的这一部分是我系统的瓶颈,我需要非常快的速度。

为了让代码正常工作,我选择了黑暗面

因为Dapper把我的列表变成了参数。SQL Server不能处理很多参数。我以前从未需要过甚至两位数的参数。我必须使用动态SQL

所以我的解决方案是:

string listOfIdsJoined = "("+String.Join(",", listOfIds.ToArray())+")";
connection.Execute("delete from myTable where Id in " + listOfIdsJoined);
在大家拿起手电筒和干草叉之前,让我解释一下

此代码在服务器上运行,该服务器的唯一输入是来自大型机系统的数据馈送。 我动态创建的列表是一个long/bigint列表。 long/bigint来自标识列。
我知道构建动态SQL是不好的,但在这种情况下,我看不出它是如何导致安全风险的。

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

在SQL Server中,大容量加载是一种经过优化的路径,应该非常快

例如:

执行语句CREATE TABLE RowsToDeleteID INT PRIMARY KEY 使用大容量加载将键插入行删除 执行从myTable中删除,其中Id在SELECT Id FROM RowsToDelete中 执行DROP TABLE RowsToDelte如果关闭会话,表也将自动删除 假设使用简洁的代码示例:

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));

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

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

这将起作用。

@marc_s-我不需要传递那么多参数。。。但我确实需要按PK Id删除那么多行。不过我这样做对我来说没问题。我告诉dapper删除我的@列表中的每一行。正是Dapper在为我的列表中的每一项创建参数。从这些小信息很难判断,但为什么不能使用批处理的选择标准作为删除的标准呢。或者在MyTable中有一个processed标志,在processing中设置它,然后使用它。它不是brill,但比逐个删除它们要快得多。即使有10000条记录,也不会太糟糕。我的批处理标准不是很好。所以我不想用这个。我可以添加一个processed标志,但要做到这一点,我需要一种方法来调用要添加processed标志的行。如果我能把它们叫出,我还不如把它们删除。我可以添加一个标志,表示在选择的时间批处理。但我不希望这样。添加的实际使用SqlBulkCopy的示例代码可以通过向临时表和数据表添加更多列来适应更广泛的表。@Pure.Krome可能他的listOfIds是List类型的,因此可能不需要清理输入。。。但假设是万恶之源。其次,一般建议=>动态创建sql脚本并将其转换为字符串。。。结果可能非常糟糕:这将为listOfIds中的每个Id创建单独的查询。
connection.Execute("delete from myTable where Id in (@Id)", listOfIds.AsEnumerable().Select(i=> new { Id = i }).ToList());