where =?的最佳做法,准备好的陈述中的(?)条款在哪里?

时间:2010-02-25 12:42:46

标签: sql database performance prepared-statement

使用带有一个问号的预备声明五十次,或使用带有五十个问号的预备声明一次是否更高效?

基本上是Where Person = ?还是Where Person IN (?, ?, ?, ...)更好?

实施例

假设您有一个包含列,国家/地区的表格,然后是几个关系表,那么您就拥有该国家/地区的人口。

鉴于1000个国家的名单,获得人口的最佳方式是什么?

请记住,这是一个假设的例子Wikipedia puts the number of countries at 223,让我们假设这个例子更大。

  1. 创建一个包含a的语句 国家参数并返回一个人口。 示例:Where Country = ?

  2. 创建预备声明 动态地,添加一个?为每个人 使用Where in (?,?,etc)子句的国家/地区。示例:Where Country = (?, ?, ...)

  3. 创建一个 像选项中的简单陈述 一,但循环并重用 一个参数Prepared Statement for each 国家

  4. 什么是更好的方法?

6 个答案:

答案 0 :(得分:4)

我在项目中达到了一个点,我能够测试一些真实的数据。

根据1435项,选项1需要约8分钟,选项2需要约15秒,选项3需要约3分钟。

选项2在性能方面是明显的赢家。编码有点困难,但性能差异太大而不容忽视。

我有理由认为,来回查看数据库是瓶颈,但我确信此处列出的结果会因网络,数据库引擎,数据库机器规格和其他环境因素而异。

答案 1 :(得分:0)

正如人们常说的那样,“这取决于”。如果你只是在寻找一个国家的人口,我会选择方法1.我会避免使用#2,因为我不喜欢使用动态构造的SQL,除非它是完成工作的唯一方法(有效地),这似乎不是这些情况之一。我在#3上并不大,因为我认为如果你需要获取所有不同国家的人口,那么循环效率会很低。

我们如何添加#4:一个返回所有国家/地区的人口的语句,如

SELECT C.COUNTRY_NAME, SUM(S.POPULATION)
  FROM COUNTRY C,
       COUNTRY_CENSUS_SUBDIVISION S
  WHERE S.ID_COUNTRY = C.ID_COUNTRY
  GROUP BY C.COUNTRY_NAME;

围绕该方法建立一种方法,如果您需要一次性获得所有国家/地区的人口,请将国家/地区的地图返回给人口。

分享并享受。

答案 2 :(得分:0)

RAM很便宜。将整个列表加载到缓存的哈希表中并以内存速度工作

如果性能问题,请使用RAM。您可能需要花费数天或数周的时间来优化可能符合价值100美元的RAM的内容

答案 3 :(得分:0)

执行查询有两个步骤:
1.制定执行计划 2.执行计划。

预备语句与步骤1相关。在给出的示例中,我认为最多的执行时间将在步骤2中,因此我选择提供最佳执行的替代方案。使数据库引擎优化的一般规则是给出范围问题,而不是在发出几个小问题的客户端中循环。可用的索引和客户端 - 服务器延迟当然会影响差异的大小,但我认为您的选项#2,动态创建预准备语句通常是最佳选择。

您是否对不同的替代方案进行过任何测试?如果你有,他们会展示什么?

答案 4 :(得分:0)

正如其他人所说,这取决于参数的数量和数据的大小。根据您在评论中所述,源表可能是具有数十万行的内容。如果是这种情况,问题归结为允许的过滤输入的数量。您的查询是仅允许一小部分输入还是需要允许过滤一千个国家/地区?如果是后者,那么我建议将选择存储到中间表中并加入其中。类似的东西:

Create Table CriteriaSelections
(
    SessionOrUsername nvarchar(50) not null
    , Country nvarchar(50) not null
)

在选择时,您将填充此表,然后从中查询

Select ...
From BigFatCountryTable
    Join CriteriaSelections
        On CriteriaSelections.Country = BigFatCountryTable.Country
            And CriteriaSelections.SessionOrUsername = @SessionOrUsername

如果可以通过相同的“会话”并行地以不同方式多次调用,则可以使用RNGCryptoServiceProvider生成随机数。此设置的缺点是您需要定期清除选择表。

如果有问题的实体有些不可改变(例如国家,城市等),那么将缓存策略与您的查询策略结合使用也会有所帮助。

BTW,沿着同样的路线的另一个解决方案是使用临时表。但是,如果这样做,则需要小心使用完全相同的连接来创建临时表,临时表的填充及其使用。

答案 5 :(得分:0)

根据使用的数据库引擎,可能还有其他选择。

例如,对于MS SQL,您可以使用CSV-> Table函数,例如: http://www.nigelrivett.net/SQLTsql/ParseCSVString.html

然后,您可以使用逗号分隔的值字符串为查询提供,并加入表格:

SELECT ..
FROM  table t
INNER JOIN dbo.fn_ParseCSVString(?, ',') x
     ON  x.s = t.id
WHERE ...

在这种情况下,将有两个循环:构建CSV字符串(如果您还没有以此格式使用它)并将CSV拆分为表格。

但它可以提供比执行连接几次以及使用IN更好的性能(根据我的经验,它具有非常糟糕的性能)。如果性能确实是一个问题,那么你当然应该进行测试。

结果也可能因网络开销等而异......