2

我正在为我的班级编写一个私有方法。我将一个整数列表作为参数传递给这个整数列表,表示我的 SQL Server 2008 表中一行的 ID。

我希望在传入的整数之一等于 a 的所有行上返回 (a 列)List<string>的a 。所以如果我通过."Name""ID"List<int> {1, 2, 3 }

我想基本上运行命令(SELECT Name FROM Table WHERE ID = 1 OR ID = 2 OR ID = 3).ToList<string>()

我正在使用的数据库非常繁忙,因此尽可能优化我的解决方案非常重要。考虑到这一点,我想知道使用 .dbml 文件创建指向该数据库的链接并使用 Linq to SQL 查询数据库是否是更好的做法?

或者只是创建一个 SQLCommand 对象,执行一次,遍历阅读器并将其保存在列表中?执行此操作的最佳方法是什么?创建一个 .dbml 文件来代表一个非常繁忙的数据库是不好的做法吗?

4

5 回答 5

5

创建 .dbml 对服务器端性能影响不大;这会改变调用端的工具 - 但服务器不会真正注意到来自 .dbml 的命令与手动编码的命令之间的区别,至少:不是这样简单的事情(我应该注意,对于复杂的查询,手动编码查询通常可以胜过机器生成的查询)。

在调用者的表现方面;.dbml 只是所有常用命令/阅读器/等的包装- 它不能让事情变得更快。在某些情况下,如果它不能很好地解析表达式,或者没有缓存解析的结果(就 TSQL 而言),它可能会使其变慢。

不过,我要说的是,dapper为你很好地处理这个问题:

var ids = new List<int>{1,2,3};
var names = conn.Select<string>("select Name from Table where ID in @ids",
      new {ids}).ToList();

dapper 将发现in @ids用法,并将其扩展为参数,执行:

select Name from Table where ID in (@p__0, @p__1, @p__2)

(或类似的东西) - 将 1、2 和 3 作为这些值传递。

这给了你:

  • 方便来电者
  • 调用者的性能(dapper 被高度优化)
  • 全参数化
    • 允许在服务器上优化查询计划重用

一般地说,dapper 也将愉快地处理一般实体映射,例如:

int id = 12345;
var customer = conn.Select<Customer>("select * from Custom where Id = @id",
    new { id }).Single();
于 2012-07-26T09:43:56.553 回答
2

我会做的几件事:

A. 使用表值参数

CREATE TYPE LocationTableType AS TABLE 
( ID INT);
GO

B. 使用存储过程(与您的 TVP)

CREATE PROCEDURE dbo. usp_GetLocationNames
    @TVP LocationTableType READONLY
    AS 
    SET NOCOUNT ON;
    SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;

    SELECT Name
    FROM dbo.Location l
    JOIN @TVP t ON l.ID = t.ID

C. 允许脏读——SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;

D. 不计算行数 - SET NOCOUNT ON;

E. 将结果集缓存一段时间

由于我对您的应用程序或您的情况知之甚少,因此这些项目“通常”是我对大多数 proc 会做的事情。显然,如果您在分发现金之前检查某人的银行账户余额,您将不允许脏读,也不会缓存结果集。但在大多数情况下,这些都是可以接受的。

于 2012-07-26T09:50:06.117 回答
0

如果您按数字 ID 选择,那么动态形成 WHERE 子句是安全的(即 WHERE ID IN (1,2,3,...)

更高级的方法是使用 XML 参数创建 SP。示例代码片段:

DECLARE @xmlIds AS XML
SET @xmlIds = '<Ids><ID>1</ID><ID>2</ID></Ids>'

SELECT Name FROM Table
WHERE ID IN (
    SELECT
        Data.row.value('.', 'INT')
        FROM
        @XmlIds.nodes('/Ids/ID') As Data(row))
于 2012-07-26T09:50:11.210 回答
0

为了限制流量最好减少到数据库的往返次数,如果您只发出一个命令,也许使用 IN 子句而不是多个 or 并参数化您的查询,那么更好。

于 2012-07-26T09:31:21.593 回答
0

您可以使用本机 C# 和 Sql 2008 在本机完成所有这些操作。在 Sql 2008 中,它引入了用户定义的表类型和存储过程的表值参数

因此,以下内容将为您提供您想要的,

CREATE TYPE UdtId AS TABLE
(
    [ID] INT NOT NULL
    PRIMARY KEY NONCLUSTERED ([ID] ASC)
)

CREATE PROCEDURE spGetCustomerByIds
    @IDS UdtId READONLY
AS
BEGIN
    SELECT
        C.*
    FROM Customer C
    INNER JOIN UdtId I ON
        C.ID = I.ID
END

希望它背后的 C# 代码是显而易见的,但它看起来像,

public foo GetCustomerDataByIds(IEnumerable<int> ids)
{
    using (var command = new SqlCommand())
    using (var adatper = new SqlAdapter())
    using (var dataSet = new DataSet())
    {
        command.Text = "spGetCustomerByIds";
        command.CommandType = CommandType.StoredProcedure;
        command.Parameters.AddWithValue("@IDS", GetDataTableOfIds(ids));
        // execute and return the stuff you're after
    }
}

private DataTable GetDataTableOfIds(IEnumerable<int> ids)
{
    var table = new DataTable();
    table.Columns.Add(new DataColumns("ID", typeof(int));
    foreach (var id in ids)
    {
        table.Rows.Add(id);
    }
    return table;
}
于 2012-07-26T09:53:56.527 回答