使用带有一个问号的预备声明五十次,或使用带有五十个问号的预备声明一次是否更高效?
基本上是Where Person = ?
还是Where Person IN (?, ?, ?, ...)
更好?
假设您有一个包含列,国家/地区的表格,然后是几个关系表,那么您就拥有该国家/地区的人口。
鉴于1000个国家的名单,获得人口的最佳方式是什么?
请记住,这是一个假设的例子Wikipedia puts the number of countries at 223,让我们假设这个例子更大。
创建一个包含a的语句
国家参数并返回一个人口。
示例:Where Country = ?
创建预备声明
动态地,添加一个?为每个人
使用Where in
(?,?,etc)
子句的国家/地区。示例:Where Country = (?, ?, ...)
创建一个 像选项中的简单陈述 一,但循环并重用 一个参数Prepared Statement for each 国家
什么是更好的方法?
答案 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更好的性能(根据我的经验,它具有非常糟糕的性能)。如果性能确实是一个问题,那么你当然应该进行测试。
结果也可能因网络开销等而异......