索引限制和解决方法
本文讨论索引提供者及其限制和解决方法。
Neo4j 中有两种索引类型:btree 和全文索引。本文针对 btree 索引,在 4.0 之前称为模式索引。这是通过 Cypher 创建索引或索引支持约束时获得的普通索引。
CREATE INDEX "My index" FOR (p:Person) ON (p.name)
所有索引都由索引提供者支持。全文索引由 fulltext-1.0
支持,btree 索引由 native-btree-1.0
(默认)或 lucene+native-3.0
支持。
下表列出了可用的 btree 索引提供者及其对原生索引的支持
索引提供者 | 支持原生索引的值类型 |
---|---|
|
所有类型均为原生 |
|
单属性字符串为 Lucene,其余为原生 |
键大小限制
native-btree-1.0
索引提供者具有 8167 字节的键大小限制。根据键是否保存单个字符串、单个数组或多个值(即键是否在复合索引中),此限制以不同的方式表现出来。
如果事务达到一个或多个更改的键大小限制,则该事务将在提交任何更改之前失败。如果在索引填充期间达到限制,则生成的索引将处于失败状态,因此不可用于任何查询。
有关如何计算原生索引的键大小的详细信息,请参见下文。
如果键不适合此限制,则很可能全文索引更适合用例,如果不是,则 lucene+native-3.0
的键大小限制为 32766 字节。
包含和以…结尾的查询
native-btree-1.0
索引提供者对 ENDS WITH
和 CONTAINS
查询的支持有限。这些查询无法像使用 STARTS WITH
、=
和 <>
的查询那样进行优化搜索。相反,索引结果将是带有过滤的索引扫描的流。
对于单属性字符串,可以使用 lucene+native-3.0
代替,它完全支持 ENDS WITH
和 CONSTAINS
。
要使用与默认值不同的提供者创建索引,最简单的方法是使用 db.createIndex
、db.createUniquePropertyConstraint
或 db.createNodeKey
过程,您可以向其中提供索引提供者名称。另一种选择是使用 dbms.index.default_schema_provider
配置默认索引提供者。请注意,此配置选项需要重新启动才能生效。
键大小计算
本部分描述了如何计算原生索引的键大小。
如键大小部分所述,在使用 native-btree-1.0
索引提供者时,键大小存在限制。本附录详细描述了如何计算大小。
元素大小计算
在计算结果键的总大小时,了解如何计算单个值的大小非常有用。在某些情况下,这些条目大小会因条目是否在数组中而异。
类型 | elementSizeifSingle * |
elementSizeifInArray ** |
---|---|---|
|
3 |
1 |
|
4 |
2 |
|
6 |
4 |
|
10 |
8 |
|
6 |
4 |
|
10 |
8 |
|
2 |
1 |
|
9 |
8 |
|
13 |
12 |
|
9 |
8 |
|
17 |
16 |
|
13 |
12 |
|
29 |
28 |
|
29 |
28 |
|
28 |
24 |
|
36 |
32 |
|
28 |
24 |
|
36 |
32 |
|
|
|
|
† |
不支持嵌套数组 |
* elementSizeifSingle
表示如果是一个单个条目,则条目的大小。
** elementSizeifInArray
表示如果是一个条目的一部分,则条目的大小。
*** utf8StringSize
是使用 UTF8 编码的String
的字节大小。
† elementSizeArray
是数组元素的大小,使用以下公式计算
-
如果数组的数据类型是数值数据类型
elementSizeArray = 4 + ( arrayLength * elementSizeifInArray )
-
如果数组的数据类型是几何数据类型
elementSizeArray = 6 + ( arrayLength * elementSizeifInArray )
-
如果数组的数据类型是非数值类型
elementSizeArray = 3 + ( arrayLength * elementSizeifInArray )
使用 UTF8 编码字符串
值得注意的是,常见的字符(如字母、数字和一些符号)会转换为每个字符一个字节。非拉丁字符可能占用多个字节。因此,例如,如果包含多字节字符,则包含 100 个字符或更少字符的字符串可能大于 100 字节。 更具体地说,字符串的相关字节长度是在使用UTF8 编码时。 |
考虑字符串 His name was Måns Lööv
。
此字符串有 19 个字符,每个字符占用 1 个字节。此外,还有 3 个字符,每个字符占用 2 个字节,总共增加 6 个字节。因此,使用 UTF8 编码的String
的字节大小(即 utf8StringSize)为 25 个字节。
如果此字符串是原生索引的一部分,则我们得到
elementSize = 2 + utf8StringSize = 2 + 25 = 27 个字节
考虑数组 [19, 84, 20, 11, 54, 9, 59, 76, 82, 27, 9, 35, 56, 80, 65, 95, 16, 91, 61, 11]。
此数组有 20 个Int
类型的元素。由于它们在数组中,因此我们需要使用 elementSizeifInArray
,对于 Int
来说是 4
。
应用数值数据类型数组的公式,我们得到
elementSizeArray = 4 + ( arrayLength * elementSizeifInArray ) = 4 + ( 20 * 4 ) = 84 个字节
非复合索引
非复合索引违反大小限制的唯一方法是值是长字符串或大型数组。
字符串
非复合索引中的字符串具有 8164 字节的键大小限制。
数组
非复合索引中的数组使用以下公式
1 + elementSizeArray =< 8167
这里 elementSizeArray
是从元素大小 计算得到的数字。
如果我们倒着数,我们可以得到每种数据类型的精确数组长度限制
-
maxArrayLength = FLOOR( ( 8167 - 4 ) / elementSizeifInArray )
对于数值类型。 -
maxArrayLength = FLOOR( ( 8167 - 4 ) / elementSizeifInArray )
对于非数值类型。
这些计算得出了以下表格
数据类型 | maxArrayLength |
---|---|
|
8163 |
|
4081 |
|
2040 |
|
1020 |
|
2040 |
|
1020 |
|
8164 |
|
请参见字符串的最大数组长度示例 |
|
1020 |
|
680 |
|
1020 |
|
510 |
|
680 |
|
291 |
|
291 |
|
340 |
|
255 |
|
340 |
|
255 |
请注意,在大多数情况下,Cypher 会在处理数字时使用 Long
或 Double
。
类型为 String
的属性是一个特殊情况,因为它们是动态大小的。下表显示了数组中数组元素的最大数量,基于特定字符串大小
字符串大小 | maxArrayLength |
---|---|
1 |
2721 |
10 |
680 |
100 |
80 |
1000 |
8 |
此表格可以用作参考点。例如:如果我们知道数组中的所有字符串都占用 100 字节或更少,则长度为 80 或更低的数组一定会适合。
复合索引
此限制仅在满足以下一个或多个条件时适用
-
复合索引包含字符串
-
复合索引包含数组
-
复合索引针对许多不同的属性(>50 个)
我们称复合索引的目标属性为插槽
。例如,对 :Person(firstName, surName, age)
的索引有三个属性,因此有三个插槽。
在索引中,每个插槽都由一个元素填充。为了计算索引的大小,我们必须知道索引中每个元素的大小,即elementSize
,如前几部分所述。
可以使用以下等式验证特定复合索引条目是否在范围内
sum( elementSize ) =< 8167
在这里,sum( elementSize )
是所有复合键元素大小的总和,如 [index-configuration-limitations-element-size-calculations] 中 elementSizeifSingle
所定义。
考虑一个包含五个字符串的复合索引,每个字符串最多可以占用 500 字节。
使用上面的公式,我们得到
sum( elementSize ) = 5 * ( 3 + 500 ) = 2515 < 8167
我们的复合索引完全在限制范围内。
考虑一个包含 10 个类型为 Float
的数组的复合索引,每个数组的长度为 250。
首先我们计算每个数组元素的大小
elementSizeArray = 4 + ( arrayLength * elementSizeifInArray ) = 4 + ( 250 * 4 ) = 1004
然后我们计算复合索引的大小
sum( elementSizeArray ) = 10 * 1004 = 10040 > 8167
此索引键将超过原生索引的键大小限制。
此页面是否有用?