Cypher 计划程序的索引提示
计划程序提示用于在为查询构建执行计划时影响计划程序的决策。计划程序提示使用USING
关键字在查询中指定。
强制计划程序行为是一项高级功能,应谨慎使用,仅供经验丰富的开发人员和/或数据库管理员使用,因为它可能会导致查询性能下降。 |
执行查询时,Neo4j 需要确定在查询图中的哪个位置开始匹配。这是通过查看MATCH
子句和WHERE
条件并使用这些信息来查找有用的索引或其他起点来完成的。
但是,所选索引并不总是最佳选择。有时多个索引可能是候选索引,并且查询计划程序会从性能的角度选择次优的索引。此外,在某些情况下(尽管很少见),完全不使用索引会更好。
可以通过USING
关键字强制 Neo4j 使用特定的起点。这称为给出计划程序提示。
计划程序提示有三种类型
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.25 Batch size 128 +-----------------+----------------------------------------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+ | Operator | Details | Estimated Rows | Rows | DB Hits | Memory (Bytes) | Page Cache Hits/Misses | Time (ms) | Pipeline | +-----------------+----------------------------------------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+ | +ProduceResults | c, cc, i, p, s, sc | 0 | 0 | 0 | | | | | | | +----------------------------------------------------------+----------------+------+---------+----------------+ | | | | +Filter | s.born = $autoint_0 AND s:Scientist | 0 | 0 | 0 | | | | | | | +----------------------------------------------------------+----------------+------+---------+----------------+ | | | | +Expand(All) | (sc)<-[anon_0:RESEARCHED]-(s) | 0 | 0 | 0 | | | | | | | +----------------------------------------------------------+----------------+------+---------+----------------+ | | | | +Filter | i.year = $autoint_1 AND sc:Science | 0 | 0 | 0 | | | | | | | +----------------------------------------------------------+----------------+------+---------+----------------+ | | | | +Expand(All) | (p)-[i:INVENTED_BY]->(sc) | 0 | 0 | 0 | | | | | | | +----------------------------------------------------------+----------------+------+---------+----------------+ | | | | +Filter | p.born = $autoint_2 AND p:Pioneer | 0 | 0 | 2 | | | | | | | +----------------------------------------------------------+----------------+------+---------+----------------+ | | | | +Expand(All) | (c)<-[anon_1:LIVES_IN]-(p) | 1 | 1 | 3 | | | | | | | +----------------------------------------------------------+----------------+------+---------+----------------+ | | | | +Filter | c:City | 1 | 1 | 2 | | | | | | | +----------------------------------------------------------+----------------+------+---------+----------------+ | | | | +Expand(All) | (cc)<-[anon_2:PART_OF]-(c) | 1 | 1 | 2 | | | | | | | +----------------------------------------------------------+----------------+------+---------+----------------+ | | | | +NodeIndexSeek | RANGE INDEX cc:Country(formed) WHERE formed = $autoint_3 | 1 | 1 | 2 | 120 | 6/1 | 0.506 | Fused in Pipeline 0 | +-----------------+----------------------------------------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+ Total database accesses: 11, total allocated memory: 208
索引提示
索引提示用于指定计划程序应使用哪个索引作为起点。在查询所使用的特定值的索引统计信息不准确的情况下,这可能是有益的,这会导致计划程序选择非最佳索引。索引提示在适用的MATCH
子句之后提供。
可用的索引提示为
提示 | 计划满足 |
---|---|
|
|
|
|
|
|
|
|
在为提示指定索引类型(例如RANGE
、TEXT
或POINT
)时,仅当存在指定类型的索引时才能满足该提示。当未指定索引类型时,任何索引类型都可以满足该提示。
使用提示绝不能更改查询的结果。因此,仅当计划程序知道使用指定类型的索引不会更改结果时,才能满足具有指定索引类型的提示。有关更多详细信息,请参阅索引的使用。 |
可以提供多个索引提示,但请记住,多个起点需要在查询计划的后面使用潜在的昂贵连接。
使用节点索引提示的查询
上面的查询可以进行调整以选择不同的索引作为起点。
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.25 Batch size 128 +-----------------+-----------------------------------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+ | Operator | Details | Estimated Rows | Rows | DB Hits | Memory (Bytes) | Page Cache Hits/Misses | Time (ms) | Pipeline | +-----------------+-----------------------------------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+ | +ProduceResults | c, cc, i, p, s, sc | 0 | 0 | 0 | | | | | | | +-----------------------------------------------------+----------------+------+---------+----------------+ | | | | +Filter | cc.formed = $autoint_3 AND cc:Country | 0 | 0 | 0 | | | | | | | +-----------------------------------------------------+----------------+------+---------+----------------+ | | | | +Expand(All) | (c)-[anon_2:PART_OF]->(cc) | 0 | 0 | 0 | | | | | | | +-----------------------------------------------------+----------------+------+---------+----------------+ | | | | +Filter | c:City | 0 | 0 | 0 | | | | | | | +-----------------------------------------------------+----------------+------+---------+----------------+ | | | | +Expand(All) | (p)-[anon_1:LIVES_IN]->(c) | 0 | 0 | 0 | | | | | | | +-----------------------------------------------------+----------------+------+---------+----------------+ | | | | +Filter | s.born = $autoint_0 AND s:Scientist | 0 | 0 | 0 | | | | | | | +-----------------------------------------------------+----------------+------+---------+----------------+ | | | | +Expand(All) | (sc)<-[anon_0:RESEARCHED]-(s) | 0 | 0 | 0 | | | | | | | +-----------------------------------------------------+----------------+------+---------+----------------+ | | | | +Filter | i.year = $autoint_1 AND sc:Science | 0 | 0 | 2 | | | | | | | +-----------------------------------------------------+----------------+------+---------+----------------+ | | | | +Expand(All) | (p)-[i:INVENTED_BY]->(sc) | 2 | 2 | 6 | | | | | | | +-----------------------------------------------------+----------------+------+---------+----------------+ | | | | +NodeIndexSeek | RANGE INDEX p:Pioneer(born) WHERE born = $autoint_2 | 2 | 2 | 3 | 120 | 4/1 | 0.491 | Fused in Pipeline 0 | +-----------------+-----------------------------------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+ Total database accesses: 11, total allocated memory: 208
使用节点文本索引提示的查询
以下查询可以进行调整以选择文本索引。
PROFILE
MATCH (c:Country)
USING TEXT INDEX c:Country(name)
WHERE c.name = 'Country7'
RETURN *
Planner COST Runtime PIPELINED Runtime version 5.25 Batch size 128 +-----------------+-------------------------------------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+ | Operator | Details | Estimated Rows | Rows | DB Hits | Memory (Bytes) | Page Cache Hits/Misses | Time (ms) | Pipeline | +-----------------+-------------------------------------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+ | +ProduceResults | c | 1 | 1 | 0 | | | | | | | +-------------------------------------------------------+----------------+------+---------+----------------+ | | | | +NodeIndexSeek | TEXT INDEX c:Country(name) WHERE name = $autostring_0 | 1 | 1 | 2 | 120 | 2/0 | 0.949 | Fused in Pipeline 0 | +-----------------+-------------------------------------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+ Total database accesses: 2, total allocated memory: 184
使用关系索引提示的查询
上面的查询可以进行调整以选择关系索引作为起点。
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.25 Batch size 128 +--------------------------------+---------------------------------------------------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+ | Operator | Details | Estimated Rows | Rows | DB Hits | Memory (Bytes) | Page Cache Hits/Misses | Time (ms) | Pipeline | +--------------------------------+---------------------------------------------------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+ | +ProduceResults | c, cc, i, p, s, sc | 0 | 0 | 0 | | | | | | | +---------------------------------------------------------------------+----------------+------+---------+----------------+ | | | | +Filter | cc.formed = $autoint_3 AND cc:Country | 0 | 0 | 0 | | | | | | | +---------------------------------------------------------------------+----------------+------+---------+----------------+ | | | | +Expand(All) | (c)-[anon_2:PART_OF]->(cc) | 0 | 0 | 0 | | | | | | | +---------------------------------------------------------------------+----------------+------+---------+----------------+ | | | | +Filter | c:City | 0 | 0 | 0 | | | | | | | +---------------------------------------------------------------------+----------------+------+---------+----------------+ | | | | +Expand(All) | (p)-[anon_1:LIVES_IN]->(c) | 0 | 0 | 0 | | | | | | | +---------------------------------------------------------------------+----------------+------+---------+----------------+ | | | | +Filter | s.born = $autoint_0 AND s:Scientist | 0 | 0 | 0 | | | | | | | +---------------------------------------------------------------------+----------------+------+---------+----------------+ | | | | +Expand(All) | (sc)<-[anon_0:RESEARCHED]-(s) | 0 | 0 | 0 | | | | | | | +---------------------------------------------------------------------+----------------+------+---------+----------------+ | | | | +Filter | p.born = $autoint_2 AND sc:Science AND p:Pioneer | 0 | 0 | 4 | | | | | | | +---------------------------------------------------------------------+----------------+------+---------+----------------+ | | | | +DirectedRelationshipIndexSeek | RANGE INDEX (p)-[i:INVENTED_BY(year)]->(sc) WHERE year = $autoint_1 | 2 | 2 | 3 | 120 | 5/1 | 0.461 | Fused in Pipeline 0 | +--------------------------------+---------------------------------------------------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+ Total database accesses: 7, total allocated memory: 208
使用关系文本索引提示的查询
以下查询可以进行调整以选择文本索引。
PROFILE
MATCH ()-[i:INVENTED_BY]->()
USING TEXT INDEX i:INVENTED_BY(location)
WHERE i.location = 'Location7'
RETURN *
Planner COST Runtime PIPELINED Runtime version 5.25 Batch size 128 +--------------------------------+----------------------------------------------------------------------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+ | Operator | Details | Estimated Rows | Rows | DB Hits | Memory (Bytes) | Page Cache Hits/Misses | Time (ms) | Pipeline | +--------------------------------+----------------------------------------------------------------------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+ | +ProduceResults | i | 1 | 1 | 0 | | | | | | | +----------------------------------------------------------------------------------------+----------------+------+---------+----------------+ | | | | +DirectedRelationshipIndexSeek | TEXT INDEX (anon_0)-[i:INVENTED_BY(location)]->(anon_1) WHERE location = $autostring_0 | 1 | 1 | 2 | 120 | 3/0 | 1.079 | Fused in Pipeline 0 | +--------------------------------+----------------------------------------------------------------------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+ Total database accesses: 2, total allocated memory: 184
使用多个索引提示的查询
提供一个索引提示更改了查询的起点,但计划仍然是线性的,这意味着它只有一个起点。如果我们再给计划程序另一个索引提示,我们强制它使用两个起点,一个在匹配的每一端。然后,它将使用连接运算符连接这两个分支。
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.25 Batch size 128 +------------------+----------------------------------------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+ | Operator | Details | Estimated Rows | Rows | DB Hits | Memory (Bytes) | Page Cache Hits/Misses | Time (ms) | Pipeline | +------------------+----------------------------------------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+ | +ProduceResults | c, cc, i, p, s, sc | 0 | 0 | 0 | | 0/0 | 0.000 | | | | +----------------------------------------------------------+----------------+------+---------+----------------+------------------------+-----------+ | | +NodeHashJoin | sc | 0 | 0 | 0 | 432 | | | In Pipeline 2 | | |\ +----------------------------------------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+ | | +Expand(All) | (s)-[anon_0:RESEARCHED]->(sc) | 1 | 0 | 0 | | | | | | | | +----------------------------------------------------------+----------------+------+---------+----------------+ | | | | | +NodeIndexSeek | RANGE INDEX s:Scientist(born) WHERE born = $autoint_0 | 1 | 0 | 0 | 120 | 0/0 | 0.000 | Fused in Pipeline 1 | | | +----------------------------------------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+ | +Filter | i.year = $autoint_1 AND sc:Science | 0 | 0 | 0 | | | | | | | +----------------------------------------------------------+----------------+------+---------+----------------+ | | | | +Expand(All) | (p)-[i:INVENTED_BY]->(sc) | 0 | 0 | 0 | | | | | | | +----------------------------------------------------------+----------------+------+---------+----------------+ | | | | +Filter | p.born = $autoint_2 AND p:Pioneer | 0 | 0 | 2 | | | | | | | +----------------------------------------------------------+----------------+------+---------+----------------+ | | | | +Expand(All) | (c)<-[anon_1:LIVES_IN]-(p) | 1 | 1 | 3 | | | | | | | +----------------------------------------------------------+----------------+------+---------+----------------+ | | | | +Filter | c:City | 1 | 1 | 2 | | | | | | | +----------------------------------------------------------+----------------+------+---------+----------------+ | | | | +Expand(All) | (cc)<-[anon_2:PART_OF]-(c) | 1 | 1 | 2 | | | | | | | +----------------------------------------------------------+----------------+------+---------+----------------+ | | | | +NodeIndexSeek | RANGE INDEX cc:Country(formed) WHERE formed = $autoint_3 | 1 | 1 | 2 | 120 | 7/0 | 0.494 | Fused in Pipeline 0 | +------------------+----------------------------------------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+ Total database accesses: 11, total allocated memory: 768
使用多个索引提示进行查询
如果查询在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.25 Batch size 128 +-----------------------+------------------------------------------------------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+ | Operator | Details | Estimated Rows | Rows | DB Hits | Memory (Bytes) | Page Cache Hits/Misses | Time (ms) | Pipeline | +-----------------------+------------------------------------------------------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+ | +ProduceResults | country | 1 | 1 | 0 | | | | | | | +------------------------------------------------------------------------+----------------+------+---------+----------------+ | | | | +Distinct | country | 1 | 1 | 0 | 224 | | | | | | +------------------------------------------------------------------------+----------------+------+---------+----------------+ | | | | +Union | | 2 | 1 | 0 | 80 | 1/0 | 0.213 | Fused in Pipeline 2 | | |\ +------------------------------------------------------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+ | | +NodeIndexSeek | RANGE INDEX country:Country(formed) WHERE formed = $autoint_0 | 1 | 1 | 2 | 120 | 1/0 | 0.101 | In Pipeline 1 | | | +------------------------------------------------------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+ | +NodeIndexSeekByRange | RANGE INDEX country:Country(name) WHERE name STARTS WITH $autostring_1 | 1 | 0 | 1 | 120 | 0/1 | 0.307 | In Pipeline 0 | +-----------------------+------------------------------------------------------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+ Total database accesses: 3, total allocated memory: 320
Cypher®通常会提供一个使用所有索引进行析取的计划,无需提示。但是,如果谓词似乎选择性不高,它可能会决定改为计划一个NodeByLabelScan
。在这种情况下,索引提示可能会有用。
扫描提示
如果您的查询匹配索引的大部分内容,扫描标签或关系类型并过滤掉不匹配的行可能会更快。为此,您可以在适用的MATCH
子句之后使用USING SCAN variable:Label
(用于节点索引)和USING SCAN variable:RELATIONSHIP_TYPE
(用于关系索引)。这将强制Cypher不使用可能已使用的索引,而是执行标签扫描/关系类型扫描。您可以使用相同的提示来强制执行没有索引适用的起始点。
提示标签扫描
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.25 Batch size 128 +------------------+-----------------------------------------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+ | Operator | Details | Estimated Rows | Rows | DB Hits | Memory (Bytes) | Page Cache Hits/Misses | Time (ms) | Pipeline | +------------------+-----------------------------------------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+ | +ProduceResults | c, cc, i, p, s, sc | 0 | 0 | 0 | | | | | | | +-----------------------------------------------------------+----------------+------+---------+----------------+ | | | | +Filter | cc.formed = $autoint_3 AND cc:Country | 0 | 0 | 0 | | | | | | | +-----------------------------------------------------------+----------------+------+---------+----------------+ | | | | +Expand(All) | (c)-[anon_2:PART_OF]->(cc) | 0 | 0 | 0 | | | | | | | +-----------------------------------------------------------+----------------+------+---------+----------------+ | | | | +Filter | c:City | 0 | 0 | 0 | | | | | | | +-----------------------------------------------------------+----------------+------+---------+----------------+ | | | | +Expand(All) | (p)-[anon_1:LIVES_IN]->(c) | 0 | 0 | 0 | | | | | | | +-----------------------------------------------------------+----------------+------+---------+----------------+ | | | | +Filter | i.year = $autoint_1 AND p.born = $autoint_2 AND p:Pioneer | 0 | 0 | 1 | | | | | | | +-----------------------------------------------------------+----------------+------+---------+----------------+ | | | | +Expand(All) | (sc)<-[i:INVENTED_BY]-(p) | 1 | 1 | 3 | | | | | | | +-----------------------------------------------------------+----------------+------+---------+----------------+ | | | | +Filter | sc:Science | 1 | 1 | 2 | | | | | | | +-----------------------------------------------------------+----------------+------+---------+----------------+ | | | | +Expand(All) | (s)-[anon_0:RESEARCHED]->(sc) | 1 | 1 | 2 | | | | | | | +-----------------------------------------------------------+----------------+------+---------+----------------+ | | | | +Filter | s.born = $autoint_0 | 1 | 1 | 200 | | | | | | | +-----------------------------------------------------------+----------------+------+---------+----------------+ | | | | +NodeByLabelScan | s:Scientist | 100 | 100 | 101 | 120 | 11/0 | 0.512 | Fused in Pipeline 0 | +------------------+-----------------------------------------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+ Total database accesses: 309, total allocated memory: 216
提示关系类型扫描
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.25 Batch size 128 +-------------------------------+--------------------------------------------------------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+ | Operator | Details | Estimated Rows | Rows | DB Hits | Memory (Bytes) | Page Cache Hits/Misses | Time (ms) | Pipeline | +-------------------------------+--------------------------------------------------------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+ | +ProduceResults | c, cc, i, p, s, sc | 0 | 0 | 0 | | | | | | | +--------------------------------------------------------------------------+----------------+------+---------+----------------+ | | | | +Filter | cc.formed = $autoint_3 AND cc:Country | 0 | 0 | 0 | | | | | | | +--------------------------------------------------------------------------+----------------+------+---------+----------------+ | | | | +Expand(All) | (c)-[anon_2:PART_OF]->(cc) | 0 | 0 | 0 | | | | | | | +--------------------------------------------------------------------------+----------------+------+---------+----------------+ | | | | +Filter | c:City | 0 | 0 | 0 | | | | | | | +--------------------------------------------------------------------------+----------------+------+---------+----------------+ | | | | +Expand(All) | (p)-[anon_1:LIVES_IN]->(c) | 0 | 0 | 0 | | | | | | | +--------------------------------------------------------------------------+----------------+------+---------+----------------+ | | | | +Filter | s.born = $autoint_0 AND s:Scientist | 0 | 0 | 0 | | | | | | | +--------------------------------------------------------------------------+----------------+------+---------+----------------+ | | | | +Expand(All) | (sc)<-[anon_0:RESEARCHED]-(s) | 0 | 0 | 0 | | | | | | | +--------------------------------------------------------------------------+----------------+------+---------+----------------+ | | | | +Filter | i.year = $autoint_1 AND p.born = $autoint_2 AND sc:Science AND p:Pioneer | 0 | 0 | 204 | | | | | | | +--------------------------------------------------------------------------+----------------+------+---------+----------------+ | | | | +DirectedRelationshipTypeScan | (p)-[i:INVENTED_BY]->(sc) | 100 | 100 | 101 | 120 | 9/0 | 0.910 | Fused in Pipeline 0 | +-------------------------------+--------------------------------------------------------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+ Total database accesses: 305, total allocated memory: 208
使用多个扫描提示进行查询
如果查询在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.25 Batch size 128 +------------------------+--------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+ | Operator | Details | Estimated Rows | Rows | DB Hits | Memory (Bytes) | Page Cache Hits/Misses | Time (ms) | Pipeline | +------------------------+--------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+ | +ProduceResults | person | 180 | 200 | 0 | | | | | | | +--------------------------+----------------+------+---------+----------------+ | | | | +UnionNodeByLabelsScan | person:Pioneer|Scientist | 180 | 200 | 202 | 120 | 6/0 | 1.740 | Fused in Pipeline 0 | +------------------------+--------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+ Total database accesses: 202, total allocated memory: 184
Cypher通常会提供一个使用扫描进行析取的计划,无需提示。但是,如果标签谓词似乎选择性不高,它可能会决定改为计划一个AllNodeScan
,后面跟着一个Filter
。在这种情况下,扫描提示可能会有用。
连接提示
连接提示是最高级别的提示类型,不用于查找查询执行计划的起始点,而是用于强制在指定点进行连接。这意味着计划中必须存在多个起始点(叶子),以便查询能够连接从这些叶子向上延伸的两个分支。由于这种性质,连接以及随后的连接提示将强制规划器寻找其他起始点,并且在没有更多好的起始点的情况下,可能会选择一个非常糟糕的起始点。这将对查询性能产生负面影响。在其他情况下,提示可能会强制规划器选择一个看起来很糟糕的起始点,而实际上它被证明是一个非常好的起始点。
提示单个节点上的连接
在上面使用多个索引提示的示例中,我们看到规划器选择进行连接,但不是在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.25 Batch size 128 +------------------+------------------------------------------------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+ | Operator | Details | Estimated Rows | Rows | DB Hits | Memory (Bytes) | Page Cache Hits/Misses | Time (ms) | Pipeline | +------------------+------------------------------------------------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+ | +ProduceResults | c, cc, i, p, s, sc | 0 | 0 | 0 | | 0/0 | 0.000 | | | | +------------------------------------------------------------------+----------------+------+---------+----------------+------------------------+-----------+ | | +NodeHashJoin | p | 0 | 0 | 0 | 432 | | | In Pipeline 2 | | |\ +------------------------------------------------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+ | | +Filter | cache[p.born] = $autoint_2 | 1 | 0 | 0 | | | | | | | | +------------------------------------------------------------------+----------------+------+---------+----------------+ | | | | | +Expand(All) | (c)<-[anon_1:LIVES_IN]-(p) | 1 | 0 | 0 | | | | | | | | +------------------------------------------------------------------+----------------+------+---------+----------------+ | | | | | +Filter | c:City | 1 | 0 | 0 | | | | | | | | +------------------------------------------------------------------+----------------+------+---------+----------------+ | | | | | +Expand(All) | (cc)<-[anon_2:PART_OF]-(c) | 1 | 0 | 0 | | | | | | | | +------------------------------------------------------------------+----------------+------+---------+----------------+ | | | | | +NodeIndexSeek | RANGE INDEX cc:Country(formed) WHERE formed = $autoint_3 | 1 | 0 | 0 | 120 | 0/0 | 0.000 | Fused in Pipeline 1 | | | +------------------------------------------------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+ | +Filter | i.year = $autoint_1 AND cache[p.born] = $autoint_2 AND p:Pioneer | 0 | 0 | 1 | | | | | | | +------------------------------------------------------------------+----------------+------+---------+----------------+ | | | | +Expand(All) | (sc)<-[i:INVENTED_BY]-(p) | 1 | 1 | 3 | | | | | | | +------------------------------------------------------------------+----------------+------+---------+----------------+ | | | | +Filter | sc:Science | 1 | 1 | 2 | | | | | | | +------------------------------------------------------------------+----------------+------+---------+----------------+ | | | | +Expand(All) | (s)-[anon_0:RESEARCHED]->(sc) | 1 | 1 | 2 | | | | | | | +------------------------------------------------------------------+----------------+------+---------+----------------+ | | | | +NodeIndexSeek | RANGE INDEX s:Scientist(born) WHERE born = $autoint_0 | 1 | 1 | 2 | 120 | 6/1 | 0.515 | Fused in Pipeline 0 | +------------------+------------------------------------------------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+ Total database accesses: 10, total allocated memory: 768
提示可选匹配的连接
连接提示也可用于强制规划器选择NodeLeftOuterHashJoin
或NodeRightOuterHashJoin
来解决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.25 Batch size 128 +----------------------+-------------------------------------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+ | Operator | Details | Estimated Rows | Rows | DB Hits | Memory (Bytes) | Page Cache Hits/Misses | Time (ms) | Pipeline | +----------------------+-------------------------------------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+ | +ProduceResults | s, sc | 1 | 1 | 0 | | | | | | | +-------------------------------------------------------+----------------+------+---------+----------------+ | | | | +OptionalExpand(All) | (s)-[anon_0:RESEARCHED]->(sc) WHERE sc:Science | 1 | 1 | 4 | | | | | | | +-------------------------------------------------------+----------------+------+---------+----------------+ | | | | +NodeIndexSeek | RANGE INDEX s:Scientist(born) WHERE born = $autoint_0 | 1 | 1 | 2 | 120 | 6/0 | 0.560 | Fused in Pipeline 0 | +----------------------+-------------------------------------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+ Total database accesses: 6, total allocated memory: 184
PROFILE
MATCH (s:Scientist {born: 1850})
OPTIONAL MATCH (s)-[:RESEARCHED]->(sc:Science)
USING JOIN ON s
RETURN *
现在规划器使用连接来解决OPTIONAL MATCH
。
Planner COST Runtime PIPELINED Runtime version 5.25 Batch size 128 +------------------------+-------------------------------------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+ | Operator | Details | Estimated Rows | Rows | DB Hits | Memory (Bytes) | Page Cache Hits/Misses | Time (ms) | Pipeline | +------------------------+-------------------------------------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+ | +ProduceResults | s, sc | 1 | 1 | 0 | | 2/0 | 0.213 | | | | +-------------------------------------------------------+----------------+------+---------+----------------+------------------------+-----------+ | | +NodeLeftOuterHashJoin | s | 1 | 1 | 0 | 3112 | | 0.650 | In Pipeline 2 | | |\ +-------------------------------------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+ | | +Expand(All) | (sc)<-[anon_0:RESEARCHED]-(s) | 100 | 100 | 300 | | | | | | | | +-------------------------------------------------------+----------------+------+---------+----------------+ | | | | | +NodeByLabelScan | sc:Science | 100 | 100 | 101 | 120 | 4/0 | 0.786 | Fused in Pipeline 1 | | | +-------------------------------------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+ | +NodeIndexSeek | RANGE INDEX s:Scientist(born) WHERE born = $autoint_0 | 1 | 1 | 2 | 120 | 1/0 | 0.214 | In Pipeline 0 | +------------------------+-------------------------------------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+ Total database accesses: 403, total allocated memory: 3192