Apache Geode - 查询连接性能
Apache Geode - Query performance on joins
我正在使用 Apache Geode 作为缓存解决方案。我需要在 2 个不同的区域内存储数据并使用简单的连接查询检索它们。
我尝试了复制区域和分区区域,但发现查询需要很长时间才能获得 return 结果。我也在这两个区域上添加了索引,这提高了性能,但仍然不够快。有人可以帮助提高此查询的性能吗?
这是我试过的
示例 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;
}
能否描述一下您的域对象? Employees 和 Department 区域中的键和值是什么?您在使用 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,它将能够在结果从服务器到达时逐块处理。
我正在使用 Apache Geode 作为缓存解决方案。我需要在 2 个不同的区域内存储数据并使用简单的连接查询检索它们。
我尝试了复制区域和分区区域,但发现查询需要很长时间才能获得 return 结果。我也在这两个区域上添加了索引,这提高了性能,但仍然不够快。有人可以帮助提高此查询的性能吗?
这是我试过的
示例 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;
}
能否描述一下您的域对象? Employees 和 Department 区域中的键和值是什么?您在使用 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,它将能够在结果从服务器到达时逐块处理。