使用 Progress 查询索引中的不等式
Query with inequality in index using Progress
在 Progress 4GL 中使用不等式查询记录的最快方法是什么?例如,如果我需要查找状态字段与 'MI' 不匹配的所有记录,我将如何编写以获得最佳性能?为什么?
我被告知的各种解决方案包括使用更广泛或不同的索引,然后使用 IF 语句,以避免使用不等式,例如:
FOR EACH record NO-LOCK:
IF record.state = "MI" THEN NEXT.
/*do stuff*/
END.
有人告诉我避免使用 NE
语句,因为它们会降低性能,
FOR EACH record NO-LOCK
WHERE record.state NE "MI":
/*do stuff slowly, apparently*/
END.
但我也被告知使用 OR 也是邪恶的。
FOR EACH record NO-LOCK
WHERE record.state = "WI" OR "AL":
/*didn't write all 49 minus MI for space*/
END.
我没有得到实质性的证据来证明为什么这三个中的任何一个会更好,而且我的开发环境中没有足够的数据来测试我正在处理的实际情况。
这完全取决于您的查询与可用索引的匹配程度。
您的第一个示例执行所谓的 "table scan" - 它会在执行 IF 之前查看 table 中的每条记录以查看它是否是您想要的记录。大多数时候,这不是您想要的 ,尤其是当 table 很大或经常被查询时。
equals "=" 的性能最高,尤其是当您查询的一个或多个字段上有索引时。
"OR" 可能是邪恶的 如果 它与 "AND" 结合,就像这样:
WHERE customer.AmountDue > SomeValue AND
(customer.state = "MI" OR customer.state = "WI").
原因是数据库引擎无法使用 OR 进行任何索引查找,因此它将解析“>”运算符,然后检查与“>”匹配的每条记录,看它是否匹配两个州。
这可以通过像这样重构 WHERE 来解决:
WHERE (customer.AmountDue > SomeValue AND customer.state = "MI") OR
(customer.AmountDue > SomeValue AND customer.state = "WI").
使用这种结构,数据库引擎有两个 AND 短语,它可以解析为较小的结果集,将两个列表合并在一起,最终结果是查询遍历的单个记录集。这比在问题的第一部分使用 OR 快 多 。
这一切都归结为与您正在查询的 table 上的索引匹配的查询。如果有一个索引与您要查找的内容完全匹配,那么它会比有一个索引与您的查询部分匹配或根本没有匹配的索引要快得多。
您需要做的是查看在不同的 PUG 挑战赛会议上发表的一些精彩演讲。您可以在 PUG Challenge Americas 此处找到有关索引选择的演示文稿:
pugchallenge.org/downloads2015.html
的 "prior events" 选项卡中找到 PUG Challenge EMEA 上的演示文稿
祝你好运!
这完全取决于您真正想做什么以及实际的数据和索引是什么。
幸运的是,您可以使用类似于以下的线束来测试这些东西:
define variable i as integer no-undo.
define variable lr as integer no-undo.
find _myconnection no-lock.
find _userio no-lock where _userio-id = _myconn-userid + 1.
lr = _userio-dbaccess.
for each metric-desc no-lock /* query to test goes here... */
where db-id < 1600 or db-id > 1600:
i = i + 1.
end.
find _userio no-lock where _userio-id = _myconn-userid + 1.
lr = _userio-dbaccess - lr.
display lr i.
在这种情况下,我有一个名为 "metric-desc" 的 table。它恰好有一个索引,其主要组成部分是一个名为 "db-id" 的字段。有点像有一个名为 "state".
的字段
它有 13,358 条记录。
有 52 条记录的 db-id = 1600(我凭空抽取了 1600,很像 state = "MI")。
如果我注释掉 WHERE 子句并阅读整个内容,我会得到 26,994 "logical reads"(索引条目加上记录)这是数据库引擎为解析查询所做的工作。
如果我使用 "db-id <> 1600"(类似于您示例中的 "state <> 'MI' "),我会得到相同的结果——整个 table 都被扫描了。
如果我用显示的 OR 替换那个 where 子句,那么它需要 26,892 次逻辑读取——没有读取 db-id = 1600 的记录。
就一般经验法则而言,“=”是你的朋友,“<>”通常是不好的(事实并非如此)。如果您能想出一种方法来将某些内容表示为“=”,那将是最有效的。范围匹配(“<”、“<=”、“>”、“>=”不如“<>”好,但比“<>”好)或者可能没问题——这取决于索引和你的放置方式一起查询。
最重要的索引规则是在前导组件上使用尽可能多的相等匹配。一旦你背离了那个规则,你就在做出妥协。
在 Progress 4GL 中使用不等式查询记录的最快方法是什么?例如,如果我需要查找状态字段与 'MI' 不匹配的所有记录,我将如何编写以获得最佳性能?为什么?
我被告知的各种解决方案包括使用更广泛或不同的索引,然后使用 IF 语句,以避免使用不等式,例如:
FOR EACH record NO-LOCK:
IF record.state = "MI" THEN NEXT.
/*do stuff*/
END.
有人告诉我避免使用 NE
语句,因为它们会降低性能,
FOR EACH record NO-LOCK
WHERE record.state NE "MI":
/*do stuff slowly, apparently*/
END.
但我也被告知使用 OR 也是邪恶的。
FOR EACH record NO-LOCK
WHERE record.state = "WI" OR "AL":
/*didn't write all 49 minus MI for space*/
END.
我没有得到实质性的证据来证明为什么这三个中的任何一个会更好,而且我的开发环境中没有足够的数据来测试我正在处理的实际情况。
这完全取决于您的查询与可用索引的匹配程度。
您的第一个示例执行所谓的 "table scan" - 它会在执行 IF 之前查看 table 中的每条记录以查看它是否是您想要的记录。大多数时候,这不是您想要的 ,尤其是当 table 很大或经常被查询时。
equals "=" 的性能最高,尤其是当您查询的一个或多个字段上有索引时。
"OR" 可能是邪恶的 如果 它与 "AND" 结合,就像这样:
WHERE customer.AmountDue > SomeValue AND
(customer.state = "MI" OR customer.state = "WI").
原因是数据库引擎无法使用 OR 进行任何索引查找,因此它将解析“>”运算符,然后检查与“>”匹配的每条记录,看它是否匹配两个州。
这可以通过像这样重构 WHERE 来解决:
WHERE (customer.AmountDue > SomeValue AND customer.state = "MI") OR
(customer.AmountDue > SomeValue AND customer.state = "WI").
使用这种结构,数据库引擎有两个 AND 短语,它可以解析为较小的结果集,将两个列表合并在一起,最终结果是查询遍历的单个记录集。这比在问题的第一部分使用 OR 快 多 。
这一切都归结为与您正在查询的 table 上的索引匹配的查询。如果有一个索引与您要查找的内容完全匹配,那么它会比有一个索引与您的查询部分匹配或根本没有匹配的索引要快得多。
您需要做的是查看在不同的 PUG 挑战赛会议上发表的一些精彩演讲。您可以在 PUG Challenge Americas 此处找到有关索引选择的演示文稿:
pugchallenge.org/downloads2015.html
的 "prior events" 选项卡中找到 PUG Challenge EMEA 上的演示文稿祝你好运!
这完全取决于您真正想做什么以及实际的数据和索引是什么。
幸运的是,您可以使用类似于以下的线束来测试这些东西:
define variable i as integer no-undo.
define variable lr as integer no-undo.
find _myconnection no-lock.
find _userio no-lock where _userio-id = _myconn-userid + 1.
lr = _userio-dbaccess.
for each metric-desc no-lock /* query to test goes here... */
where db-id < 1600 or db-id > 1600:
i = i + 1.
end.
find _userio no-lock where _userio-id = _myconn-userid + 1.
lr = _userio-dbaccess - lr.
display lr i.
在这种情况下,我有一个名为 "metric-desc" 的 table。它恰好有一个索引,其主要组成部分是一个名为 "db-id" 的字段。有点像有一个名为 "state".
的字段它有 13,358 条记录。
有 52 条记录的 db-id = 1600(我凭空抽取了 1600,很像 state = "MI")。
如果我注释掉 WHERE 子句并阅读整个内容,我会得到 26,994 "logical reads"(索引条目加上记录)这是数据库引擎为解析查询所做的工作。
如果我使用 "db-id <> 1600"(类似于您示例中的 "state <> 'MI' "),我会得到相同的结果——整个 table 都被扫描了。
如果我用显示的 OR 替换那个 where 子句,那么它需要 26,892 次逻辑读取——没有读取 db-id = 1600 的记录。
就一般经验法则而言,“=”是你的朋友,“<>”通常是不好的(事实并非如此)。如果您能想出一种方法来将某些内容表示为“=”,那将是最有效的。范围匹配(“<”、“<=”、“>”、“>=”不如“<>”好,但比“<>”好)或者可能没问题——这取决于索引和你的放置方式一起查询。
最重要的索引规则是在前导组件上使用尽可能多的相等匹配。一旦你背离了那个规则,你就在做出妥协。