什么是无限查询?

时间:2010-06-18 08:29:20

标签: sql database

是没有'WHERE param = value'语句的查询吗?

为此简单而道歉...

2 个答案:

答案 0 :(得分:8)

无界查询是搜索条件不是特别具体的查询,因此很可能返回非常大的结果集。没有WHERE子句的查询肯定会属于这个类别,但我们暂时考虑其他一些可能性。假设我们有如下表格:

CREATE TABLE SALES_DATA
  (ID_SALES_DATA      NUMBER PRIMARY KEY,
   TRANSACTION_DATE   DATE NOT NULL
   LOCATION           NUMBER NOT NULL,
   TOTAL_SALE_AMOUNT  NUMBER NOT NULL,
   ...etc...);

CREATE TABLE LOCATION
  (LOCATION  NUMBER PRIMARY KEY,
   DISTRICT  NUMBER NOT NULL,
   ...etc...);

假设我们想要引入特定交易,并且我们知道销售的ID:

SELECT * FROM SALES_DATA WHERE ID_SALES_DATA = <whatever>

在这种情况下,查询是有界的,我们可以保证它会拉入一行或零行。

有界查询的另一个例子,但结果集很大,是23区主任说“我想看看去年每天在我所在地区的每家商店的总销售额”,就像

SELECT LOCATION, TRUNC(TRANSACTION_DATE), SUM(TOTAL_SALE_AMOUNT)
  FROM SALES_DATA S,
       LOCATION L
  WHERE S.TRANSACTION_DATE BETWEEN '01-JAN-2009' AND '31-DEC-2009' AND
        L.LOCATION = S.LOCATION AND
        L.DISTRICT = 23
  GROUP BY LOCATION,
           TRUNC(TRANSACTION_DATE)
  ORDER BY LOCATION,
           TRUNC(TRANSACTION_DATE)

在这种情况下,查询应返回区域23中每个商店的365(或更少,如果商店不是每天开放)行。如果区域中有25个商店,它将返回9125行或更少。

另一方面,假设我们的销售副总裁想要一些数据。他/她/它不太确定想要什么,但他/她/它非常肯定无论发生在一年的前六个月......不太确定哪个一年......也不确定这个位置 - 可能是在23区(他/她与过去6年经营23区的个人发生了争执,自那场高尔夫锦标赛以来......好吧,没关系......但是如果问题可以挂在23区的导演的门上,那么就这样吧!)......当然他/她/它想要所有的细节,并把它放在他/她/它的桌子很甜!因此我们得到一个类似于

的查询
SELECT L.DISTRICT, S.LOCATION, S.TRANSACTION_DATE,
       S.something, S.something_else, S.some_more_stuff
  FROM SALES_DATA S,
       LOCATIONS L
  WHERE EXTRACT(MONTH FROM S.TRANSACTION_DATE) <= 6 AND
        L.LOCATION = S.LOCATION
  ORDER BY L.DISTRICT,
           S.LOCATION

这是无限查询的示例。它会返回多少行?好问题 - 这取决于商业条件如何,开放的地点数量,2月份的天数等等。

更简单地说,如果你可以查看一个查询并且非常清楚它将返回多少行(即使这个数字可能相对较大),查询也是有界限的。如果你做不到,那就没有限制了。

分享并享受。

答案 1 :(得分:0)

http://hibernatingrhinos.com/Products/EFProf/learn#UnboundedResultSet

无界结果集是执行查询的位置,并未明确限制查询返回结果的数量。通常,这意味着应用程序假定查询始终只返回几条记录。这在开发和测试中都很有效,但它是一个等待在生产中爆炸的定时炸弹。

查询可能会突然开始返回数千行,在某些情况下,它可能会返回数百万行。这会导致数据库服务器,应用程序服务器和网络上的负载增加。在许多情况下,它可以使整个系统停止运行,通常以应用程序服务器因内存不足错误而崩溃而结束。

以下是将触发无界结果集警告的查询的一个示例:

var query = from post in blogDataContext.Posts
            where post.Category == "Performance"
            select post;

如果性能类别有很多帖子,我们将加载所有帖子,这可能不是预期的。通过使用Take()方法使用分页可以很容易地解决这个问题:

var query = (from post in blogDataContext.Posts            
            where post.Category == "Performance"            
            select post)
            .Take(15);

现在我们确信我们只需要处理可预测的小结果集,如果我们需要处理所有这些结果集,我们可以根据需要翻阅记录。分页是使用Skip()方法实现的,该方法指示实体框架在进入下一页之前跳过(在数据库级别)N条记录。

但是直接遍历对象图还存在另一个常见的无界结果集问题,如下例所示:

var post = postRepository.Get(id);
foreach (var comment in post.Comments)
{
    // do something interesting with the comment
}

在这里,我们再次加载整个集合,而不考虑结果集的大小。在遍历对象图时,实体框架不提供对集合进行分页的好方法。建议您对集合的内容发出单独的显式查询,这样您就可以浏览该集合,而无需将太多数据加载到内存中。