什么时候'IN'和什么时候不?

时间:2009-07-20 12:52:54

标签: java database performance jdbc java-ee

让我们假设您正在为零售连锁店撰写应用程序。因此,您可以设计对象模型,以便将“Store”定义为核心业务对象和许多支持对象。假设'Store'如下所示:

class Store implements Validatable{
int storeNo;
int storeName;
... etc.... 
}

因此,您的客户告诉您必须将Excel商店日程表从Excel工具箱导入到应用程序中,您必须在其上运行一系列验证。例如,'StoreIsInSameCountry';'StoreIsValid'等等。因此,您将设计一个规则界面来检查所有业务条件。像这样:

interface Rule T extends Validatable> {
public Error check(T value) throws Exception;
}

现在,问题来了。我正在从这个excel表上传2000个商店。因此,我最终会多次运行为商店定义的每个规则。如果我对数据库有4个规则= 8000个查询,即连接池有16000个命中。对于我只需要检查商店是否存在的简单检查,查询将是:

 SELECT STORE_ATTRIB1, STORE_ATTRIB2... from STORE where STORE_ID = ?

这样我就可以获得我的'Store'对象。当我从数据库中没有得到任何东西时,那个商店就不存在了。因此,对于这样一个简单的检查,我将不得不为2000个商店点击数据库2000次。

或者,我可以这样做:

SELECT STORE_ATTRIB1, STORE_ATTRIB2... from STORE where STORE_ID in (1,2,3..... ) 

这个查询实际上返回的速度要快于2000次以上的查询。 但是,对于只能为单个商店运行规则的设计,它并不顺利。

我知道使用IN不是建议的方法。那么,你认为我应该怎么做?我应该继续在这里使用IN,因为它在这种情况下会提供更好的性能吗?或者我应该改变我的设计?

如果你穿着我会做什么,最佳做法是什么?

4 个答案:

答案 0 :(得分:2)

  

这样我就可以从数据库中获取我的'Store'对象。当我从数据库中没有得到任何东西时,那个商店就不存在了。因此,对于这样一个简单的检查,我必须为2000个商店点击数据库2000次。

这是不应该做的事情。

创建一个临时表,在表格中填入您的值和JOIN此表格,如下所示:

SELECT  STORE_ATTRIB1, STORE_ATTRIB2...
FROM    temptable tt
JOIN    STORE s
ON      s.STORE_ID = t.id

或者这个:

SELECT  STORE_ATTRIB1, STORE_ATTRIB2...
FROM    STORE s
WHERE   s.STORE_ID IN
        (
        SELECT  id
        FROM    temptable tt
        )
  

我知道使用IN不是建议的方法。那么,你认为我应该怎么做?我应该继续在这里使用IN,因为它在这种情况下会提供更好的性能吗?或者我应该改变我的设计?

IN过滤器重复出来。

如果您希望为列表中的每个重复值选择每个符合条件的行,请使用JOIN

IN绝不是“不建议的方法论”。

事实上,曾经有一段时间某些数据库没有高效地支持IN查询,这就是为什么民间智慧仍然建议不要使用它。

但是如果您的store_id被正确编入索引(并且很可能是,如果它看起来是PRIMARY KEY),那么主要数据库的所有现代版本(即OracleSQL ServerMySQLPostgreSQL)将使用有效的计划来执行此查询。

请参阅我的博客中的这篇文章,了解SQL Server中的效果详情:

请注意,在设计合理的数据库中,验证规则也是基于集合的。

予。即您将验证规则实施为针对temptable的查询。

但是,要支持旧规则,您可以从temptable row-by-agonizing-row中选择值,应用规则并删除未通过验证的值。

答案 1 :(得分:1)

SELECT store_id FROM store WHERE store_active = 1

甚至

SELECT store_id FROM store

会告诉您单个查询中的所有活动商店。您现在可以对您知道存在的商店进行其他测试,并且您已经为数据库节省了1,999次点击。

如果您有相对无争议的数据库访问权限,并且没有时间限制整个事情要花多长时间,那么您就不必担心一遍又一遍地访问连接池。毕竟,这就是它的设计目标!

答案 2 :(得分:0)

我认为这更像是一个商业问题,其中包含客户运行导入的频率参数,实施任一解决方案所需的时间,以及每小时的时间费用。

如果它偶尔运行一次,我认为可以接受一些不好的性能,特别是如果你能用干净的代码快速完成工作。

答案 3 :(得分:0)

...规则只能在单个商店中运行。

管理业务规则和性能是一项艰巨的任务,因此有一个库("Persistence Layer")可以做到这一点。您定义规则,然后执行大量命令,然后在一次查询中(通过使用临时表而不是'IN')从数据库中提取库,无论规则需要什么,然后将其传递给规则。 here中有一个验证程序的示例。