使用 eXist-db 中的范围索引提高查询性能
Improve performance of query with range indexes in eXist-db
阅读文档http://exist-db.org/exist/apps/doc/indexing.xml
我发现很难理解如何以及是否可以提高 'read' 查询的性能(有 2 个参数:一个字符串和一个整数)。
eXist-db 有默认的结构索引吗?我可以使用 'range index' 改进 2 参数查询吗?
关于我的 XML 数据库的更多详细信息(请注意,有 2 个不同的数据库简单地合并在同一个根上):
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<db>
<docs>
<doc>
<header>
<year>2001</year>
<number>1</number>
<type>O</type>
</header>
<metas>
<meta>
<number>26001</number>
<details>
<detail>
<description>legge</description>
<number>19</number>
<date>14/01/1994</date>
</detail>
<detail>
<description>decreto legge</description>
<number>453</number>
<date>15/11/1993</date>
</detail>
</details>
</meta>
</metas>
</doc>
<doc>
<header>
<year>2001</year>
<number>2</number>
<type>O</type>
</header>
<metas>
<meta>
<number>26002</number>
<details>
<detail>
<description>decreto legislativo</description>
<number>29</number>
<date>03/02/1993</date>
</detail>
</details>
</meta>
<meta>
<number>26016</number>
<details>
<detail>
<description>decreto legislativo</description>
<number>29</number>
<date>03/02/1993</date>
</detail>
</details>
</meta>
</metas>
</doc>
</docs>
<full_text_docs>
<doc>
<header>
<year>2001</year>
<number>1</number>
<type>O</type>
<president>ferrari</president>
</header>
<text>lorem ipsum ...
</text>
</doc>
<doc>
<header>
<year>2001</year>
<number>2</number>
<type>O</type>
<president>ferrari</president>
</header>
<text>lorem ipsum......
</text>
</doc>
</full_text_docs>
</db>
这是我的 xquery
xquery version "3.0";
let $doc := doc("/db//index_test/test_general.xml")//db/docs/doc
let $fulltxt := doc("/db//index_test/test_general.xml")//db/full_text_docs/doc
return <root> {
for $a in $doc[metas/meta/details/detail[date="03/02/1993" and number = "29"]]/header
return $fulltxt[header/year/text()=$a/year/text() and
header/number/text()=$a/number/text() and
header/type/text()=$a/type/text()
]
} </root>
基本上,我只是简单地找到与第一个数据库中的输入匹配的 detail/number
和 detail/date
,然后获取查询第二个数据库的结果。结果是所有 <full_text_header>
个匹配的文档。
我想知道是否可以为字段 number
和 date
创建索引以提高性能。请注意,这是我需要优化的唯一查询(我唯一在这个数据库上做的)显然是数字和日期更改:)。
解决方案:
要获得清晰的解释,请阅读 joewiz 的回答。我的问题是正确识别 .xconf 文件。它必须放在 /db/yourcollectiondir 中。如果您在创建文件时使用 eXide,您应该 select Xml 使用模板 "eXist-db collection configuration" 键入。当您尝试保存文件时,您会看到提示“应用配置?”然后点击 'ok'。刚才运行这个xqueryxmldb:reindex('/db/yourcollectiondir')
。
现在,如果一切正常,当您 运行 涉及索引的 xquery 时,您将在 "Monitoring and profiling".
中看到用法
正如该文档页面所述,eXist 确实为数据库中存储的所有 XML 创建了结构索引。但是,这不是值的索引,因此如果没有进一步的索引,基于值(而不是结构)的查询将涉及在 DOM 中查找值。随着数据越来越大,查找 DOM 中的值变得越来越慢。这就是基于价值的索引(例如范围索引)可以节省时间的地方。 (有关更完整的解释,请参阅 Wolfgang Meier 的 "Tuning the Database" 文章的 "Indexing" 部分,该部分对于充分利用 eXist 的性能至关重要。)
所以,是的,您可以为 <number>
和 <date>
字段创建索引。我建议使用 "new range" 索引,如该文档页面所述。设置这些索引的 collection.xconf
文件如下所示:
<collection xmlns="http://exist-db.org/collection-config/1.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<index>
<range>
<create qname="number" type="xs:integer"/>
<create qname="date" type="xs:string"/>
</range>
</index>
</collection>
您必须将其存储在 /db/system/config/
集合中,在与您的数据在数据库中的位置对应的子集合中。因此,如果您的数据位于 /db/apps/myapp/data
,您可以将此 collection.xconf
文件放在 /db/system/config/db/apps/myapp/data
.
注意这里的配置只会影响for
子句对date
和number
值的查询,而不会影响return
子句中的谓词,这取决于<year>
和 <type>
元素的值。因此,为了确保您的查询最大限度地使用索引,您应该在这些索引上声明索引; xs:integer
似乎是每个类型的合适类型。
最后,我建议删除完全无关的 /text()
步骤。有关 text()
的 use/abuse 的更多信息,请参阅 Evan Lenz 的文章 "text() is a code smell"。
更新 (2016-07-17):通过上面更新的代码示例,我有一些额外的建议。首先,由于代码在 /db/index_test
中,我们将按如下方式存储我们的文件:
假设您使用的是 eXide,当您将 collection.xconf
文件存储在一个集合中时,eXide 会提示您将该文件的副本放置在 /db/system/config
中的正确位置。如果您不使用 eXide,则需要自己将 collection.xconf
文件存储在那里。
使用未修改的查询,我可以确认尽管 collection.xconf
文件存在,但 monex 显示没有应用索引:
让我们对文件进行一些修改以确保正确应用索引:
xquery version "3.0";
<root> {
for $a in doc("/db/index_test/test_general.xml")//detail[date = "03/02/1993" and number = 29]/ancestor::doc/header
return
doc("/db/index_test/test_general.xml")/db/full_text_docs/doc
[
header/year = $a/year and
header/number = $a/number and
header/type = $a/type
]
} </root>
通过这些修改,monex 显示索引应用于 for
子句中的比较:
此处的见解来自 "Tuning the Database" 文章。要获得所有比较的完整索引,您将需要定义额外的索引,并且可能需要对您的查询进行类似的修改。
最后一点:您在这些图片中看到的 monex 版本正在使用我本周末添加的一项功能,称为 "Tare",它会尝试从查询分析结果中过滤掉其他操作,以提供帮助用户只看到他们自己的查询的效果。此功能仍然只是一个拉取请求,因此 运行 当前发布版本,您不会看到相同的结果。
阅读文档http://exist-db.org/exist/apps/doc/indexing.xml 我发现很难理解如何以及是否可以提高 'read' 查询的性能(有 2 个参数:一个字符串和一个整数)。 eXist-db 有默认的结构索引吗?我可以使用 'range index' 改进 2 参数查询吗?
关于我的 XML 数据库的更多详细信息(请注意,有 2 个不同的数据库简单地合并在同一个根上):
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<db>
<docs>
<doc>
<header>
<year>2001</year>
<number>1</number>
<type>O</type>
</header>
<metas>
<meta>
<number>26001</number>
<details>
<detail>
<description>legge</description>
<number>19</number>
<date>14/01/1994</date>
</detail>
<detail>
<description>decreto legge</description>
<number>453</number>
<date>15/11/1993</date>
</detail>
</details>
</meta>
</metas>
</doc>
<doc>
<header>
<year>2001</year>
<number>2</number>
<type>O</type>
</header>
<metas>
<meta>
<number>26002</number>
<details>
<detail>
<description>decreto legislativo</description>
<number>29</number>
<date>03/02/1993</date>
</detail>
</details>
</meta>
<meta>
<number>26016</number>
<details>
<detail>
<description>decreto legislativo</description>
<number>29</number>
<date>03/02/1993</date>
</detail>
</details>
</meta>
</metas>
</doc>
</docs>
<full_text_docs>
<doc>
<header>
<year>2001</year>
<number>1</number>
<type>O</type>
<president>ferrari</president>
</header>
<text>lorem ipsum ...
</text>
</doc>
<doc>
<header>
<year>2001</year>
<number>2</number>
<type>O</type>
<president>ferrari</president>
</header>
<text>lorem ipsum......
</text>
</doc>
</full_text_docs>
</db>
这是我的 xquery
xquery version "3.0";
let $doc := doc("/db//index_test/test_general.xml")//db/docs/doc
let $fulltxt := doc("/db//index_test/test_general.xml")//db/full_text_docs/doc
return <root> {
for $a in $doc[metas/meta/details/detail[date="03/02/1993" and number = "29"]]/header
return $fulltxt[header/year/text()=$a/year/text() and
header/number/text()=$a/number/text() and
header/type/text()=$a/type/text()
]
} </root>
基本上,我只是简单地找到与第一个数据库中的输入匹配的 detail/number
和 detail/date
,然后获取查询第二个数据库的结果。结果是所有 <full_text_header>
个匹配的文档。
我想知道是否可以为字段 number
和 date
创建索引以提高性能。请注意,这是我需要优化的唯一查询(我唯一在这个数据库上做的)显然是数字和日期更改:)。
解决方案:
要获得清晰的解释,请阅读 joewiz 的回答。我的问题是正确识别 .xconf 文件。它必须放在 /db/yourcollectiondir 中。如果您在创建文件时使用 eXide,您应该 select Xml 使用模板 "eXist-db collection configuration" 键入。当您尝试保存文件时,您会看到提示“应用配置?”然后点击 'ok'。刚才运行这个xqueryxmldb:reindex('/db/yourcollectiondir')
。
现在,如果一切正常,当您 运行 涉及索引的 xquery 时,您将在 "Monitoring and profiling".
正如该文档页面所述,eXist 确实为数据库中存储的所有 XML 创建了结构索引。但是,这不是值的索引,因此如果没有进一步的索引,基于值(而不是结构)的查询将涉及在 DOM 中查找值。随着数据越来越大,查找 DOM 中的值变得越来越慢。这就是基于价值的索引(例如范围索引)可以节省时间的地方。 (有关更完整的解释,请参阅 Wolfgang Meier 的 "Tuning the Database" 文章的 "Indexing" 部分,该部分对于充分利用 eXist 的性能至关重要。)
所以,是的,您可以为 <number>
和 <date>
字段创建索引。我建议使用 "new range" 索引,如该文档页面所述。设置这些索引的 collection.xconf
文件如下所示:
<collection xmlns="http://exist-db.org/collection-config/1.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<index>
<range>
<create qname="number" type="xs:integer"/>
<create qname="date" type="xs:string"/>
</range>
</index>
</collection>
您必须将其存储在 /db/system/config/
集合中,在与您的数据在数据库中的位置对应的子集合中。因此,如果您的数据位于 /db/apps/myapp/data
,您可以将此 collection.xconf
文件放在 /db/system/config/db/apps/myapp/data
.
注意这里的配置只会影响for
子句对date
和number
值的查询,而不会影响return
子句中的谓词,这取决于<year>
和 <type>
元素的值。因此,为了确保您的查询最大限度地使用索引,您应该在这些索引上声明索引; xs:integer
似乎是每个类型的合适类型。
最后,我建议删除完全无关的 /text()
步骤。有关 text()
的 use/abuse 的更多信息,请参阅 Evan Lenz 的文章 "text() is a code smell"。
更新 (2016-07-17):通过上面更新的代码示例,我有一些额外的建议。首先,由于代码在 /db/index_test
中,我们将按如下方式存储我们的文件:
假设您使用的是 eXide,当您将 collection.xconf
文件存储在一个集合中时,eXide 会提示您将该文件的副本放置在 /db/system/config
中的正确位置。如果您不使用 eXide,则需要自己将 collection.xconf
文件存储在那里。
使用未修改的查询,我可以确认尽管 collection.xconf
文件存在,但 monex 显示没有应用索引:
让我们对文件进行一些修改以确保正确应用索引:
xquery version "3.0";
<root> {
for $a in doc("/db/index_test/test_general.xml")//detail[date = "03/02/1993" and number = 29]/ancestor::doc/header
return
doc("/db/index_test/test_general.xml")/db/full_text_docs/doc
[
header/year = $a/year and
header/number = $a/number and
header/type = $a/type
]
} </root>
通过这些修改,monex 显示索引应用于 for
子句中的比较:
此处的见解来自 "Tuning the Database" 文章。要获得所有比较的完整索引,您将需要定义额外的索引,并且可能需要对您的查询进行类似的修改。
最后一点:您在这些图片中看到的 monex 版本正在使用我本周末添加的一项功能,称为 "Tare",它会尝试从查询分析结果中过滤掉其他操作,以提供帮助用户只看到他们自己的查询的效果。此功能仍然只是一个拉取请求,因此 运行 当前发布版本,您不会看到相同的结果。