2017-05-24 37 views
1

差别大查询

data_invoices (document, 100,000 total records, 2 tenants) 
    hash: tenantId 
    persistent: createdOn 

data_jobs (document, 10,000 total records, 2 tenants) 
    hash: tenantId 
    persistent: createdOn 

data_links (edge, 100,000 total records) 
    persistent: createdOn 
    persistent (sparse): replacedOn 

的链接集将一张发票连接到一个随机的工作,所以工作可能具有零张或多个发票。发票应该有一个或多个工作,但在我的数据中,每个发票只能匹配一个工作。 date过滤器实际上不会过滤掉任何数据(它们都小于指定的日期值),并且tenantId过滤器也不会过滤,因为所有数据都是xxxyyy

data_jobs和data_invoices的通用结构为:

tenantId: string; 
createdOn: number; 
data: [{ 
    createdOn: number; 
    values: { 
     ...collection specific data here... 
    }; 
}]; 

data_invoices收集特定数据结构是:

number: number; 
amount: number; 

data_jobs收集特定数据结构是:

name: string; 

data_的结构链接表:

createdOn: number; 
replacedOn?: number; // though I don't have any records with this value set 

createdOn场表示从1970年蜱日期值,并且是自2000年01一月到今天,日期随机。

amount字段是从10到10,000的随机货币值(小数点后两位)。

number字段是自动编号字段。

我有两个非常相似的(在我看来)查询,一种方式(发票工作)非常,非常快速地工作,另一个需要很长时间。

此查询需要1.85秒:

LET date = 1495616898128 

FOR job IN data_jobs 
    FILTER job.tenantId IN ['xxx', 'yyy'] 
    FILTER job.createdOn<=date 
    LET jobData = (job.data[* FILTER CURRENT.createdOn<=date LIMIT 1])[0] 
    FILTER CONTAINS(jobData.values.name, 'a') 
    LET invoices = (
     FOR invoice, link IN 1 INBOUND job data_links 
      FILTER link.createdOn<=date AND (link.replacedOn == NULL OR 
       link.replacedOn>date) 
      LET invoiceData = (invoice.data[* FILTER CURRENT.createdOn<=date LIMIT 1])[0] 
      FILTER invoiceData.values.amount>1000 
      COLLECT WITH COUNT INTO count 
      RETURN { 
       count 
      } 
    )[0] 
    FILTER invoices.count>0 
    SORT jobData.values.name ASC 
    LIMIT 0,8 
    RETURN job 

此查询需要8.5秒:

LET date = 1495616898128 

FOR invoice IN data_invoices 
    FILTER invoice.tenantId IN ['xxx', 'yyy'] 
    FILTER invoice.createdOn<=date 
    LET invoiceData = (invoice.data[* FILTER CURRENT.createdOn<=date LIMIT 1])[0] 
    FILTER invoiceData.values.amount>1000 
    LET jobs = (
     FOR job, link IN 1 OUTBOUND invoice data_links 
      FILTER link.createdOn<=date AND (link.replacedOn == NULL 
       OR link.replacedOn>date) 
      LET jobData = (job.data[* FILTER CURRENT.createdOn<=date LIMIT 1])[0] 
      FILTER CONTAINS(jobData.values.name, 'a') 
      COLLECT WITH COUNT INTO count 
      RETURN { 
       count 
      } 
    )[0] 
    FILTER jobs.count>0 
    SORT invoiceData.values.amount ASC 
    LIMIT 0,8 
    RETURN invoice 

我认识到这两个查询正在提供不同的数据,但处理时间应该是相同的当不可它呢?他们都通过链接表格过滤两个表格,并在另一个表格上执行聚合。我不明白为什么一种方式比另一种方式快得多。请问我能做些什么来提高这些查询的性能?

+0

在'data_jobs'中,您同时具有两个属性的过滤条件:'tenantId'和'createdOn'。如果你在两者上都创建了一个持久索引,那么你的查询的性能如何,因此将其定义为'tenantId,createdOn'。多属性索引可以真正帮助,特别是当您在同一个查询中使用这两个索引时。 –

+0

谢谢@DavidThomas我会放弃这项工作,但正如我所说的那样,这些过滤器实际上并没有带走任何记录(故意 - 我是最坏情况下的测试),并且他们可能会加快查询,让他们成为单指数,我怀疑它会很多 - 但我一定会放弃它。 – Anupheaus

+0

发表您对此内容的评论。随着调整我有一个查询,需要124秒下降到0.2秒。他们的关键是多列索引并构建查询,以便AQL引擎可以轻松确定要使用的索引。 –

回答

0

好吧,奇怪,但我偶然发现了一个非直觉的(至少对我来说)解决方案。先排序,然后过滤...

这个查询现在只需1.4秒:

LET date = 1495616898128 

FOR invoice IN data_invoices 
    FILTER invoice.tenantId IN ['xxx', 'yyy'] 
    FILTER invoice.createdOn<=date 
    LET invoiceData = (invoice.data[* FILTER CURRENT.createdOn<=date LIMIT 1])[0] 
    SORT invoiceData.values.amount ASC 
    FILTER invoiceData.values.amount>1000 
    LET jobs = (
     FOR job, link IN 1 OUTBOUND invoice data_links 
      FILTER link.createdOn<=date AND (link.replacedOn == NULL 
       OR link.replacedOn>date) 
      LET jobData = (job.data[* FILTER CURRENT.createdOn<=date LIMIT 1])[0] 
      FILTER CONTAINS(jobData.values.name, 'a') 
      COLLECT WITH COUNT INTO count 
      RETURN { 
       count 
      } 
    )[0] 
    FILTER jobs.count>0   
    LIMIT 0,8 
    RETURN invoice 

尽管在data[*].values.amount添加持久指数,它仍然不使用它(我甚至尝试SORT invoice.data[0].values.amount ASC,它仍然似乎没有使用索引?)

任何人都可以解释这个吗?