【问题标题】:Big difference in time taken to perform graph queries执行图形查询所需的时间差异很大
【发布时间】:2017-05-24 16:54:24
【问题描述】:

基于以下集合:

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_links表的结构是:

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

createdOn 字段是表示为 1970 年的刻度的日期值,是从 2000 年 1 月 1 日到今天的随机日期。

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

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

我意识到两个查询都提供了不同的数据,但处理时间应该是一样的,不是吗?它们都通过链接表过滤两个表,并且都在另一个上执行聚合。我不明白为什么一种方式比另一种方式快得多。请问有什么办法可以提高这些查询的性能吗?

【问题讨论】:

  • data_jobs 中,您同时对tenantIdcreatedOn 这两个属性有过滤条件。如果在两者上创建持久索引,查询的性能如何,因此将其定义为tenantId, createdOn。多属性索引真的很有帮助,尤其是当您在同一查询中同时使用这两种索引时。
  • 谢谢@DavidThomas,我会试一试,但就像我说的那样,这些过滤器实际上并没有带走任何记录(故意 - 我是最坏情况测试),虽然它们可能会加快速度将它们作为单个索引进行查询,我怀疑它会很多 - 不过我肯定会试一试。
  • 对您的发现发表评论。通过调整,我有一个需要 124 秒的查询下降到 0.2 秒。对我来说,关键是多列索引和构建查询,以便 AQL 引擎可以轻松确定要使用的索引。
  • 我已经向data_invoices 集合和data_jobs 集合添加了建议的持久多列索引,它根本没有任何区别。我发现虽然所花费的时间似乎都在排序中,当我删除排序时,它需要 2.5 毫秒。所以我决定在金额字段中添加一个索引(添加为data[*].values.amount,因为它位于集合中。不幸的是它没有被使用并且没有任何区别。

标签: arangodb aql


【解决方案1】:

好的,很奇怪,但我偶然发现了一个非常违反直觉(至少对我而言)的解决方案。先排序,再过滤……???

这个查询现在需要 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,它似乎仍然没有使用该索引?)

谁能解释一下?

【讨论】:

    猜你喜欢
    • 2018-10-29
    • 1970-01-01
    • 2020-07-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-15
    • 1970-01-01
    相关资源
    最近更新 更多