neo4j使用详解(十四、索引之搜索性能索引<索引提示>——最全参考)

请添加图片描述

Neo4j系列导航:
neo4j安装及简单实践
cypher语法基础
cypher插入语法
cypher插入语法
cypher查询语法
cypher通用语法
cypher函数语法
neo4j索引及调优


1.简介

计划器提示用于在为查询构建执行计划时影响计划器的决策。规划器提示在使用USING关键字的查询中指定。

强制计划器行为是一个高级特性,只有经验丰富的开发人员和/或数据库管理员才应该谨慎使用,因为它可能导致查询性能不佳。

当执行查询时,Neo4j需要决定在查询图中开始匹配的位置。这是通过查看MATCH子句和WHERE条件并使用该信息查找有用的索引或其他起点来完成的。
但是,所选的索引可能并不总是最佳选择。有时可能有多个候选索引,查询规划器从性能的角度选择次优的索引。此外,在某些情况下(尽管很少),最好根本不使用索引。
可以通过USING关键字强制Neo4j使用特定的起点。这叫做给计划提示。

有三种类型的计划提示:

  • Index hints:索引提示
  • Scan hints:扫描提示。
  • Join hints:连接提示。
PROFILE
MATCH
  (s:Scientist {born: 1850})-[:RESEARCHED]->
  (sc:Science)<-[i:INVENTED_BY {year: 560}]-
  (p:Pioneer {born: 525})-[:LIVES_IN]->
  (c:City)-[:PART_OF]->
  (cc:Country {formed: 411})
RETURN *

上面的查询将在本页的一些示例中使用。在没有任何提示的情况下,只使用一个索引而不使用连接。

查询计划:

Planner COST
Runtime PIPELINED
Runtime version 5.18
Batch size 128

OperatorDetailsEstimated RowsRowsDB HitsMemory (Bytes)Page Cache Hits/MissesTime (ms)Pipeline
+ProduceResultsc, cc, i, p, s, sc0006/10.506Fused in Pipeline 0
+Filters.born = $autoint_0 AND s:Scientist0006/10.506Fused in Pipeline 0
+Expand(All)(sc)<-[anon_0:RESEARCHED]-(s)0006/10.506Fused in Pipeline 0
+Filteri.year = $autoint_1 AND sc:Science0006/10.506Fused in Pipeline 0
+Expand(All)§-[i:INVENTED_BY]->(sc)0006/10.506Fused in Pipeline 0
+Filterp.born = $autoint_2 AND p:Pioneer0026/10.506Fused in Pipeline 0
+Expand(All)©<-[anon_1:LIVES_IN]-§1136/10.506Fused in Pipeline 0
+Filterc:City1126/10.506Fused in Pipeline 0
+Expand(All)(cc)<-[anon_2:PART_OF]-©1126/10.506Fused in Pipeline 0
+NodeIndexSeekRANGE INDEX cc:Country(formed) WHERE formed = $autoint_31121206/10.506Fused in Pipeline 0

Total database accesses: 11, total allocated memory: 208

2.索引提示(Index hints)

索引提示用于指定计划器应使用哪个索引作为起点。在索引统计信息对于已知当前查询使用的特定值不准确的情况下,这可能是有益的,这将导致计划器选择非最优索引。在适用的MATCH子句之后提供索引提示。

可用的索引提示有:

提示计划完成
USING [RANGE/TEXT/POINT] INDEX variable:Label(property)NodeIndexScan, NodeIndexSeek
USING [RANGE/TEXT/POINT] INDEX SEEK variable:Label(property)NodeIndexSeek
USING [RANGE/TEXT/POINT] INDEX variable:RELATIONSHIP_TYPE(property)DirectedRelationshipIndexScan, UndirectedRelationshipIndexScan, DirectedRelationshipIndexSeek, UndirectedRelationshipIndexSeek
USING [RANGE/TEXT/POINT] INDEX SEEK variable:RELATIONSHIP_TYPE(property)DirectedRelationshipIndexSeek, UndirectedRelationshipIndexSeek

当为提示指定索引类型时,例如RANGE、TEXT或POINT,该提示只能在指定类型的索引可用时才能实现。当没有指定索引类型时,提示可以由任何索引类型完成。

使用提示绝不能改变查询的结果。因此,只有当计划器知道使用指定类型的索引不会改变结果时,才可以实现带有指定索引类型的提示。

2.1.使用节点索引提示进行查询

实例:
可以对上面的查询进行调优,以选择不同的索引作为起点。

PROFILE
MATCH
  (s:Scientist {born: 1850})-[:RESEARCHED]->
  (sc:Science)<-[i:INVENTED_BY {year: 560}]-
  (p:Pioneer {born: 525})-[:LIVES_IN]->
  (c:City)-[:PART_OF]->
  (cc:Country {formed: 411})
USING INDEX p:Pioneer(born)
RETURN *

查询计划:

Planner COST
Runtime PIPELINED
Runtime version 5.18
Batch size 128

OperatorDetailsEstimated RowsRowsDB HitsMemory (Bytes)Page Cache Hits/MissesTime (ms)Pipeline
+ProduceResultsc, cc, i, p, s, sc0004/10.491Fused in Pipeline 0
+Filtercc.formed = $autoint_3 AND cc:Country0004/10.491Fused in Pipeline 0
+Expand(All)©-[anon_2:PART_OF]->(cc)0004/10.491Fused in Pipeline 0
+Filterc:City0004/10.491Fused in Pipeline 0
+Expand(All)§-[anon_1:LIVES_IN]->©0004/10.491Fused in Pipeline 0
+Filters.born = $autoint_0 AND s:Scientist0004/10.491Fused in Pipeline 0
+Expand(All)(sc)<-[anon_0:RESEARCHED]-(s)0004/10.491Fused in Pipeline 0
+Filteri.year = $autoint_1 AND sc:Science0024/10.491Fused in Pipeline 0
+Expand(All)§-[i:INVENTED_BY]->(sc)2264/10.491Fused in Pipeline 0
+NodeIndexSeekRANGE INDEX p:Pioneer(born) WHERE born=$autoint_22231204/10.491Fused in Pipeline 0

Total database accesses: 11, total allocated memory: 208

2.2.使用节点文本索引提示进行查询

实例:
下面的查询可以调优为选择一个文本索引。

PROFILE
MATCH (c:Country) USING TEXT INDEX c:Country(name) WHERE c.name = 'Country7' RETURN *

查询计划:

Planner COST
Runtime PIPELINED
Runtime version 5.18
Batch size 128

OperatorDetailsEstimated RowsRowsDB HitsMemory (Bytes)Page Cache Hits/MissesTime (ms)Pipeline
+ProduceResultsc1102/00.949Fused in Pipeline 0
+NodeIndexSeekTEXT INDEX c:Country(name) WHERE name = $autostring_01121202/00.949Fused in Pipeline 0

Total database accesses: 2, total allocated memory: 184

2.3.使用关系索引提示进行查询

实例:
上面的查询可以调优为选择一个关系索引作为起点。

PROFILE
MATCH
  (s:Scientist {born: 1850})-[:RESEARCHED]->
  (sc:Science)<-[i:INVENTED_BY {year: 560}]-
  (p:Pioneer {born: 525})-[:LIVES_IN]->
  (c:City)-[:PART_OF]->
  (cc:Country {formed: 411})
USING INDEX i:INVENTED_BY(year)
RETURN *

查询计划:

Planner COST
Runtime PIPELINED
Runtime version 5.18
Batch size 128

OperatorDetailsEstimated RowsRowsDB HitsMemory (Bytes)Page Cache Hits/MissesTime (ms)Pipeline
+ProduceResultsc, cc, i, p, s, sc0005/10.461Fused in Pipeline 0
+Filtercc.formed = $autoint_3 AND cc:Country0005/10.461Fused in Pipeline 0
+Expand(All)©-[anon_2:PART_OF]->(cc)0005/10.461Fused in Pipeline 0
+Filterc:City0005/10.461Fused in Pipeline 0
+Expand(All)§-[anon_1:LIVES_IN]->©0005/10.461Fused in Pipeline 0
+Filters.born = $autoint_0 AND s:Scientist0005/10.461Fused in Pipeline 0
+Expand(All)(sc)<-[anon_0:RESEARCHED]-(s)0005/10.461Fused in Pipeline 0
+Filterp.born = $autoint_2 AND sc:Science AND p:Pioneer0045/10.461Fused in Pipeline 0
+DirectedRelationshipIndexSeekRANGE INDEX §-[i:INVENTED_BY(year)]->(sc) WHERE year = $autoint_12231205/10.461Fused in Pipeline 0

Total database accesses: 7, total allocated memory: 208

2.4.使用关系文本索引提示进行查询

实例:
下面的查询可以调优为选择一个文本索引。

PROFILE
MATCH ()-[i:INVENTED_BY]->()
USING TEXT INDEX i:INVENTED_BY(location)
WHERE i.location = 'Location7'
RETURN *

查询计划:

Planner COST
Runtime PIPELINED
Runtime version 5.18
Batch size 128

OperatorDetailsEstimated RowsRowsDB HitsMemory (Bytes)Page Cache Hits/MissesTime (ms)Pipeline
+ProduceResultsi1103/01.079Fused in Pipeline 0
+DirectedRelationshipIndexSeekTEXT INDEX (anon_0)-[i:INVENTED_BY(location)]->(anon_1) WHERE location = $autostring_01121203/01.079Fused in Pipeline 0

Total database accesses: 2, total allocated memory: 184

2.5.使用多个索引提示进行查询

提供一个索引提示改变了查询的起始点,但是计划仍然是线性的,这意味着它只有一个起始点。如果我们给计划器另一个索引提示,我们就迫使它使用两个起始点,在匹配的两端各有一个。然后,它将使用连接操作符连接这两个分支。

实例:

PROFILE
MATCH
  (s:Scientist {born: 1850})-[:RESEARCHED]->
  (sc:Science)<-[i:INVENTED_BY {year: 560}]-
  (p:Pioneer {born: 525})-[:LIVES_IN]->
  (c:City)-[:PART_OF]->
  (cc:Country {formed: 411})
USING INDEX s:Scientist(born)
USING INDEX cc:Country(formed)
RETURN *

查询计划:

Planner COST
Runtime PIPELINED
Runtime version 5.18
Batch size 128

OperatorDetailsEstimated RowsRowsDB HitsMemory (Bytes)Page Cache Hits/MissesTime (ms)Pipeline
+ProduceResultsc, cc, i, p, s, sc0000/00.000In Pipeline 2
+NodeHashJoinsc000432In Pipeline 2
+Expand(All)(s)-[anon_0:RESEARCHED]->(sc)1000/00.000Fused in Pipeline 1
+NodeIndexSeekRANGE INDEX s:Scientist(born) WHERE born=$autoint_01001200/00.000Fused in Pipeline 1
+Filteri.year = $autoint_1 AND sc:Science0007/00.494Fused in Pipeline 0
+Expand(All)§-[i:INVENTED_BY]->(sc)0007/00.494Fused in Pipeline 0
+Filterp.born = $autoint_2 AND p:Pioneer0027/00.494Fused in Pipeline 0
+Expand(All)©<-[anon_1:LIVES_IN]-§1137/00.494Fused in Pipeline 0
+Filterc:City1127/00.494Fused in Pipeline 0
+Expand(All)(cc)<-[anon_2:PART_OF]-©1127/00.494Fused in Pipeline 0
+NodeIndexSeekRANGE INDEX cc:Country(formed) WHERE formed=$autoint_31121207/00.494Fused in Pipeline 0

Total database accesses: 11, total allocated memory: 768

2.6.使用带分离的多个索引提示进行查询

如果查询在WHERE子句中包含一个析取(OR),那么提供多个索引提示也很有用。这确保了所有的暗示索引都被使用,并且结果随后用Union和Distinct连接在一起。

实例:

PROFILE
MATCH (country:Country)
USING INDEX country:Country(name)
USING INDEX country:Country(formed)
WHERE country.formed = 500 OR country.name STARTS WITH "A"
RETURN *

查询计划:

Planner COST
Runtime PIPELINED
Runtime version 5.18
Batch size 128

OperatorDetailsEstimated RowsRowsDB HitsMemory (Bytes)Page Cache Hits/MissesTime (ms)Pipeline
+ProduceResultscountry1101/00.213Fused in Pipeline 2
+Distinctcountry1102241/00.213Fused in Pipeline 2
+Union210801/00.213Fused in Pipeline 2
+NodeIndexSeekRANGE INDEX country:Country(formed) WHERE formed = $autoint_01121201/00.101In Pipeline 1
+NodeIndexSeekByRangeRANGE INDEX country:Country(name) WHERE name STARTS WITH $autostring_11011200/10.307In Pipeline 0

Total database accesses: 3, total allocated memory: 320

Cypher®通常会提供一个计划,在没有提示的情况下使用所有索引进行分离。但是,如果谓词看起来不是很有选择性,它可能决定计划NodeByLabelScan。在这种情况下,索引提示可能很有用。

3.扫描提示(Scan hints)

如果您的查询匹配索引的大部分,那么扫描标签或关系类型并过滤掉不匹配的行可能会更快。 为此,您可以在适用的MATCH子句之后使用USING SCAN variable:Label用于节点索引,并使用USING SCAN variable:RELATIONSHIP_TYPE用于关系索引。这将迫使Cypher不使用本可以使用的索引,而是进行标签扫描/关系类型扫描。可以使用相同的提示来强制在不适用索引的情况下使用起点。

3.1.标签扫描提示

实例:

PROFILE
MATCH
  (s:Scientist {born: 1850})-[:RESEARCHED]->
  (sc:Science)<-[i:INVENTED_BY {year: 560}]-
  (p:Pioneer {born: 525})-[:LIVES_IN]->
  (c:City)-[:PART_OF]->
  (cc:Country {formed: 411})
USING SCAN s:Scientist
RETURN *

查询计划:

Planner COST
Runtime PIPELINED
Runtime version 5.18
Batch size 128

OperatorDetailsEstimated RowsRowsDB HitsMemory (Bytes)Page Cache Hits/MissesTime (ms)Pipeline
+ProduceResultsc, cc, i, p, s, sc00011/00.512Fused in Pipeline 0
+Filtercc.formed = $autoint_3 AND cc:Country00011/00.512Fused in Pipeline 0
+Expand(All)©-[anon_2:PART_OF]->(cc)00011/00.512Fused in Pipeline 0
+Filterc:City00011/00.512Fused in Pipeline 0
+Expand(All)§-[anon_1:LIVES_IN]->©00011/00.512Fused in Pipeline 0
+Filteri.year = $autoint_1 AND p.born = $autoint_2 AND p:Pioneer00111/00.512Fused in Pipeline 0
+Expand(All)(sc)<-[i:INVENTED_BY]-§11311/00.512Fused in Pipeline 0
+Filtersc:Science11211/00.512Fused in Pipeline 0
+Expand(All)(s)-[anon_0:RESEARCHED]->(sc)11211/00.512Fused in Pipeline 0
+Filters.born = $autoint_01120011/00.512Fused in Pipeline 0
+NodeByLabelScans:Scientist10010010112011/00.512Fused in Pipeline 0

Total database accesses: 309, total allocated memory: 216

3.2.关系类型扫描提示

实例:

PROFILE
MATCH
  (s:Scientist {born: 1850})-[:RESEARCHED]->
  (sc:Science)<-[i:INVENTED_BY {year: 560}]-
  (p:Pioneer {born: 525})-[:LIVES_IN]->
  (c:City)-[:PART_OF]->
  (cc:Country {formed: 411})
USING SCAN i:INVENTED_BY
RETURN *

查询计划:

Planner COST
Runtime PIPELINED
Runtime version 5.18
Batch size 128

OperatorDetailsEstimated RowsRowsDB HitsMemory (Bytes)Page Cache Hits/MissesTime (ms)Pipeline
+ProduceResultsc, cc, i, p, s, sc0009/00.910Fused in Pipeline 0
+Filtercc.formed = $autoint_3 AND cc:Country0009/00.910Fused in Pipeline 0
+Expand(All)©-[anon_2:PART_OF]->(cc)0009/00.910Fused in Pipeline 0
+Filterc:City0009/00.910Fused in Pipeline 0
+Expand(All)§-[anon_1:LIVES_IN]->©0009/00.910Fused in Pipeline 0
+Filters.born = $autoint_0 AND s:Scientist0009/00.910Fused in Pipeline 0
+Expand(All)(sc)<-[anon_0:RESEARCHED]-(s)0009/00.910Fused in Pipeline 0
+Filteri.year = $autoint_1 AND p.born = $autoint_2 AND sc:Science AND p:Pioneer002049/00.910Fused in Pipeline 0
+DirectedRelationshipTypeScan§-[i:INVENTED_BY]->(sc)1001001011209/00.910Fused in Pipeline 0

Total database accesses: 305, total allocated memory: 208

3.3.使用带分离的多个扫描提示进行查询

如果查询在WHERE子句中包含一个析取(OR),那么提供多个扫描提示也很有用。这确保了所有涉及的标签谓词都由UnionNodeByLabelsScan解析。

实例:

PROFILE
MATCH (person)
USING SCAN person:Pioneer
USING SCAN person:Scientist
WHERE person:Pioneer OR person:Scientist
RETURN *

查询计划:

Planner COST
Runtime PIPELINED
Runtime version 5.18
Batch size 128

OperatorDetailsEstimated RowsRowsDB HitsMemory (Bytes)Page Cache Hits/MissesTime (ms)Pipeline
+ProduceResultsperson18020006/01.740Fused in Pipeline 0
+UnionNodeByLabelsScanperson:PioneerScientist1802002021206/01.740

Total database accesses: 202, total allocated memory: 184

Cypher通常会提供一个计划,使用扫描的分离没有提示。但是,如果标签谓词看起来不是很有选择性,它可能决定计划一个AllNodeScan,然后是一个Filter`。在这种情况下,扫描提示可能很有用。

4.连接提示(join hints)

连接提示是最高级的提示类型,不用于查找查询执行计划的起始点,而是用于强制在指定点进行连接。这意味着计划中必须有多个起始点(叶),以便查询能够连接从这些叶上升的两个分支。由于这种性质,连接和随后的连接提示将迫使计划器寻找额外的起点,在没有更多好的起点的情况下,可能会选择一个非常糟糕的起点。这将对查询性能产生负面影响。在其他情况下,这个提示可能会迫使计划者选择一个看似糟糕的起点,但实际上却是一个非常好的起点。

4.1.提示单个节点上的连接

在上面使用多个索引提示的示例中,我们看到规划器选择执行连接,但不是在p节点上。通过在索引提示之外提供连接提示,我们可以强制连接发生在p节点上。

实例:

PROFILE
MATCH
  (s:Scientist {born: 1850})-[:RESEARCHED]->
  (sc:Science)<-[i:INVENTED_BY {year: 560}]-
  (p:Pioneer {born: 525})-[:LIVES_IN]->
  (c:City)-[:PART_OF]->
  (cc:Country {formed: 411})
USING INDEX s:Scientist(born)
USING INDEX cc:Country(formed)
USING JOIN ON p
RETURN *

查询计划:

Planner COST
Runtime PIPELINED
Runtime version 5.18
Batch size 128

OperatorDetailsEstimated RowsRowsDB HitsMemory (Bytes)Page Cache Hits/MissesTime (ms)Pipeline
+ProduceResultsc, cc, i, p, s, sc0000/00.000In Pipeline 2
+NodeHashJoinp000432In Pipeline 2
+Filtercache[p.born] = $autoint_21000/00.000Fused in Pipeline 1
+Expand(All)©<-[anon_1:LIVES_IN]-§1000/00.000Fused in Pipeline 1
+Filterc:City1000/00.000Fused in Pipeline 1
+Expand(All)(cc)<-[anon_2:PART_OF]-©1000/00.000Fused in Pipeline 1
+NodeIndexSeekRANGE INDEX cc:Country(formed) WHERE formed = $autoint_31001200/00.000Fused in Pipeline 1
+Filteri.year = $autoint_1 AND cache[p.born] = $autoint_2 AND p:Pioneer0016/10.515Fused in Pipeline 0
+Expand(All)(sc)<-[i:INVENTED_BY]-§1136/10.515Fused in Pipeline 0
+Filtersc:Science1126/10.515Fused in Pipeline 0
+Expand(All)(s)-[anon_0:RESEARCHED]->(sc)1126/10.515Fused in Pipeline 0
+NodeIndexSeekRANGE INDEX s:Scientist(born) WHERE born = $autoint_01121206/10.515Fused in Pipeline 0

Total database accesses: 10, total allocated memory: 768

4.2.提示单个节点上的连接

连接提示也可以用来强制计划器选择一个NodeLeftOuterHashJoinNodeRightOuterHashJoin来解决一个OPTIONAL MATCH。在大多数情况下,计划器宁愿使用OptionalExpand

实例:

PROFILE
MATCH (s:Scientist {born: 1850})
OPTIONAL MATCH (s)-[:RESEARCHED]->(sc:Science)
RETURN *

在没有任何提示的情况下,计划器没有使用连接来解决OPTIONAL MATCH。

查询计划:

Planner COST
Runtime PIPELINED
Runtime version 5.18
Batch size 128

OperatorDetailsEstimated RowsRowsDB HitsMemory (Bytes)Page Cache Hits/MissesTime (ms)Pipeline
+ProduceResultss, sc110
+OptionalExpand(All)(s)-[anon_0:RESEARCHED]->(sc) WHERE sc:Science114
+NodeIndexSeekRANGE INDEX s:Scientist(born) WHERE born = $autoint_01121206/00.560Fused in Pipeline 0

Total database accesses: 6, total allocated memory: 184

现在计划器使用连接来解决OPTIONAL MATCH。

实例:

PROFILE
MATCH (s:Scientist {born: 1850})
OPTIONAL MATCH (s)-[:RESEARCHED]->(sc:Science)
USING JOIN ON s
RETURN *

查询计划:

Planner COST
Runtime PIPELINED
Runtime version 5.18
Batch size 128

OperatorDetailsEstimated RowsRowsDB HitsMemory (Bytes)Page Cache Hits/MissesTime (ms)Pipeline
+ProduceResultss, sc1102/00.213In Pipeline 2
+NodeLeftOuterHashJoins11031120.650In Pipeline 2
+Expand(All)(sc)<-[anon_0:RESEARCHED]-(s)1001003004/00.786Fused in Pipeline 1
+NodeByLabelScansc:Science1001001011204/00.786Fused in Pipeline 1
+NodeIndexSeekRANGE INDEX s:Scientist(born) WHERE born = $autoint_01121201/00.214In Pipeline 0

Total database accesses: 403, total allocated memory: 3192

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值