2016-06-28 94 views
3

我使用Apache Geode作为缓存解决方案。我需要将数据存储在2个不同的区域中,并通过简单的连接查询来检索它们。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> 

QueryFunction

@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 - REPLICATED地区

时间从缓存中获取约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; 
} 

回答

0

能否请你描述你的域对象?员工和部门地区的关键和价值是什么?你在使用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,将能够处理结果块逐块,因为他们收到来自服务器。

+0

上述结果我尝试过使用java序列化。我改变了这个使用PDX,结果相当快。 PDX复制区域的结果现在为470毫秒。所以它看起来像序列化对性能有巨大的影响。 – Pratibha

+0

我的Employee对象的关键是empId,而我的Department对象是deptId,并且我在Employees和Department上的deptId上都创建了索引。我还有什么可以改善表现的吗?任何其他已发现可提供更好结果的序列化方法? – Pratibha

+0

我的评论太大了,不适合这里,所以最后编辑我的原始答案。 – Swapnil