java - Apache Geode - 连接查询性能

标签 java spring-data geode

我使用 Apache Geode 作为缓存解决方案。我需要将数据存储在两个不同的区域中,并通过简单的联接查询检索它们。

我尝试了复制区域和分区区域,但发现查询需要很长时间才能返回结果。我也在这两个区域添加了索引,这提高了性能,但仍然不够快。有人可以帮助解决如何提高此查询的性能吗?

这是我尝试过的

示例 1 - 分区区域

从缓存中检索约 7300 条记录所需的时间为 36 秒

cache.xml中的配置

<region name="Department">
    <region-attributes>
        <partition-attributes redundant-copies="1">
        </partition-attributes>
    </region-attributes>
    <index name="deptIndex" from-clause="/Department" expression="deptId"/>
</region>

<region name="Employee">
    <region-attributes>
        <partition-attributes redundant-copies="1" colocated-with="Department">
        </partition-attributes>
    </region-attributes>
    <index name="empIndex" from-clause="/Employee" expression="deptId"/>
</region>

查询函数

@Override
public void execute(FunctionContext context) {
// TODO Auto-generated method stub
Cache cache = CacheFactory.getAnyInstance();
QueryService queryService = cache.getQueryService();

ArrayList arguments = (ArrayList)context.getArguments();
String queryStr = (String)arguments.get(0);

Query query = queryService.newQuery(queryStr);

try {
    SelectResults result = (SelectResults)query.execute((RegionFunctionContext)context);

    ArrayList arrayResult = (ArrayList)result.asList();
    context.getResultSender().sendResult(arrayResult);
    context.getResultSender().lastResult(null);
} catch (FunctionDomainException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
} catch (TypeMismatchException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
} catch (NameResolutionException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
} catch (QueryInvocationTargetException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}

}

执行函数

Function function = new QueryFunction();
String queryStr = "SELECT * FROM /Department d, /Employee e WHERE d.deptId=e.deptId";
ArrayList argList = new ArrayList();
argList.add(queryStr);
Object result = FunctionService.onRegion(CacheFactory.getAnyInstance().getRegion("Department")).withArgs(argList).execute(function).getResult();

ArrayList resultList = (ArrayList)result;
ArrayList<StructImpl> finalList = (ArrayList)resultList.get(0);

示例 2 - 复制区域

从缓存中检索约 7300 条记录所需的时间为 29 秒

cache.xml中的配置

<region name="Department">
    <region-attributes refid="REPLICATE">
    </region-attributes>
    <index name="deptIndex" from-clause="/Department" expression="deptId"/>
</region>

<region name="Employee">
    <region-attributes refid="REPLICATE">
    </region-attributes>
    <index name="empIndex" from-clause="/Employee" expression="deptId"/>
</region>

查询

@Override
public SelectResults fetchJoinedDataForIndex() {
    QueryService queryService = getClientcache().getQueryService();
    Query query = queryService.newQuery("SELECT * FROM /Department d, /Employee e WHERE d.deptId=e.deptId");
    SelectResults result = null;
    try {
        result = (SelectResults)query.execute();
        System.out.println(result.size());
    } catch (FunctionDomainException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (TypeMismatchException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (NameResolutionException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (QueryInvocationTargetException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    return result;
}

最佳答案

您能描述一下您的域对象吗?员工和部门区域中的键和值是什么?您使用 PDX 吗?

一种简单的方法可能是将 deptId 作为部门区域的键。然后在您的函数中,您只需迭代 Employee 区域并对 Department 区域执行 get(deptId) 即可。为了进一步减少延迟,您可以将大量结果发送回客户端,同时服务器继续运行该函数。由于您提到结果中有超过 7000 个条目,因此您可以从服务器一次批量处理 500 个条目。像这样的事情:

@Override
public void execute(FunctionContext context) {
  RegionFunctionContext rfc = (RegionFunctionContext) context;
  Region<EmpId, PDXInstance> employee = PartitionRegionHelper.getLocalPrimaryData(rfc.getDataSet());
  Region<DeptId, PDXInstance> department = PartitionRegionHelper.getLocalPrimaryData(rfc.getDataSet());
  int count = 0;
  Map<PdxInstance, PdxInstance> results = new HashMap<>();
  for (Region.Entry<EmpId, PDXInstance> e : employee.entrySet()) {
    PdxInstance dept = department.get(e.getValue().get("deptId"));
    results.put(e.getValue(), dept);
    if (count == 500) {
      context.getResultSender().sendResult(results);
      results.clear();
      count = 0;
    }
  }
  context.getResultSender().lastResult(results);
}

然后在客户端上您可以使用自定义 result collector当结果从服务器到达时,它将能够逐 block 处理结果。

关于java - Apache Geode - 连接查询性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38075666/

相关文章:

spring - 使用复合键保存实体获取 ConversionNotSupportedException

java - 如何在 Spring JPA 中关闭从方法名称创建查询?

java - 关键的 gemfire 集群配置

java - 如何向 XML 元素添加属性

java - 关闭、析构和终结 : Java contradictions

java - 如何使用 HTTP 作为传输读取通过 Avro 序列化的二进制数据?

java - Hibernate 使用 findOne 和 findById 无法看到数据库中更新后触发器对记录所做的更改

java - 无法从不同节点启动geode服务器

c++ - 使用 apache geode 进行最小测试

java - 在哪里可以找到有关 Oracle Java 文档中使用的约定的信息?