Foxpro RUSHMORE 技术:一、概念
进入 FOXPRO 经常会碰到 RUSHMORE 这个东东,那么什么是 RUSHMORE 呢?我们都知道利用索引来查询数据会快得多,比如在建立了索引的字段中查询,seek 就比 locate for 要快得多,这就是因为 seek 利用了索引查询,而 locate for 没有。
那么能不能让 locate for 也能利用索引加快查询的速度呢?RUSHMORE 技术就是起这个作用的。不光是 locate for,其实凡是带 for 的命令都要做查询,比如:count for 就是统计有多少符合条件的记录,那么自然就要将符合条件的记录查询出来。而 RUSHMORE 技术可以让所有带 for 的命令加快执行速度,所以也叫优化查询。
小知识 | 为什么利用索引查询会比不利用查询快呢?一般查询是按顺序查询,比如一个表中有1000条记录,符合条件的记录在第750条,一般的查询就从第1条记录开始,一条条比较是否符合条件,直到找到符合条件的为止,很显示它必须进行750次比较。如果记录是按从小到大按顺序排列的,那么就可以不按顺序来查,可以先查第500条,如果需要找的记录比第500条大,那么符合条件的一定在500-1000之间,按同样方法再从500-1000的中间去查,就可找到750条,而750条正是要找的,因此只需两次便能找到需要的记录。 |
二、使用
别以为 RUSHMORE 这个词看起来深奥难懂,其实使用起来并不是很难,一般说来您只需要将有关的字段建立了索引就行,当执行有 for 的命令时,FOXPRO 系统会自动根据索引去查询符合条件的记录,您不需做任何事,连将所需索引设为主索引都不需要,当然如果不是结构化复合索引,您必须在查询前将索引文件打开。
三、不能使用 RUSHMORE 的情况
- 如果您在命令中用了范围子句,可能 RUSHMORE 会不起作用。我们知道范围子句有四种:all, rest, next, record n(n 用于指定一记录号),其中 all 和 rest 不会影响 RUSHMORE ,但如果使用了 next 和 record n,则 RUSHMORE 将不起作用。
- 如果建立索引时使用了 for 子句,则这个索引不能被 RUSHMORE 所采用,比如:
index on 姓名 for 基本工资>200 tag gz
这个索引就对 RUSHMORE 没有任何帮助。 - 索引表达式中如果使用了 .not. ,那么这个索引也不能被 RUSHMORE 使用,比如:
index on .not. delete() tag notdel
遇上这种情况您可以采用 set delete on ,然后再使用不带 .not. 的索引表达式。 - 当命令中使用了 while 子句。
- 如果您的电脑内存比较少, RUSHMORE 可能也不能起作用。不过我想现在的电脑很少会内存较少的。
- 对于一个已经按某个索引排序了的表,不能使用 RUSHMORE ,所以想要使用 RUSHMORE 发出命令前最好用 set order to 或 set order to 0 命令将索引设置在不对表进行控制的状态下,您不必一定要把索引关闭,对于复合索引也不可能关闭。如果一定要按某种顺序排列记录,可使用 sort 命令对记录进行实际的排序,当然这要权衡利弊了,因为 sort 命令也是很花时间的,如果为了查询时节省一点点时间,而花了大量的时间去排序,那就划不来了。假如排序一次后会大量地进行查询,那么还差不多。
当然,不能使用 RUSHMORE 并不会影响命令的正常执行,只是速度会慢一些,如果是一个很大的表,比如几百万条记录,可能会慢很多。
四、不能使用 RUSHMORE 的表达式
并不是所有的 FOR 后面跟的表达式都可以使用 RUSHMORE 来加快查询的速度,以下的表达式就不能使用 RUSHMORE 来优化:
- 带有 isblank() 和 empty() 函数的表达式是不能优化的,比如:
locate for empty(姓名) - 带有包含运算符 $ 的表达式。
locate for '稼'$姓名 - 表达式必须与索引表达式精确匹配,比如:
index on upper(cu_name) tag name &&索引表达式是 upper(cu_name)
locate for cu_name='ACME' &&不能优化,因为 cu_name 与 upper(cu_name)不是完全一样的
locate for upper(cu_name)='ACME' &&则可以优化
五、组合表达式的优化
如果是两个表达式用逻辑运算符 .or. 或 .and. 组合起来,情况就比较复杂了,下表对这种情况做了说明:
| 序号 | 表达式1 | 操作符 | 表达式2 | 查询结果 |
| 1 | 可优化 | .and. | 可优化 | 全部可优化 |
| 2 | 可优化 | .or. | 可优化 | 全部可优化 |
| 3 | 可优化 | .and. | 不可优化 | 部分可优化 |
| 4 | 可优化 | .or. | 不可优化 | 不可优化 |
| 5 | 不可优化 | .and. | 不可优化 | 不可优化 |
| 6 | 不可优化 | .or. | 不可优化 | 不可优化 |
| 7 | - | .not. | 可优化 | 全部可优化 |
| 8 | - | .not. | 不可优化 | 不可优化 |
比如:
locate for 姓名='庄稼' .and. 日期<{12/30/96} &&是全部可优化的,符合第1条
locate for 姓名='庄稼' .or. '稼'$姓名 &&不可优化,符合第4条
locate for .not. 姓名='庄稼' &&全部可优化,符合第7条
locate for .not. '稼'$姓名 &&不可优化,符合第8条
六、复杂表达式的优化
将两个组合的表达式再组合起来就形成复杂表达式,其优化的情况就更复杂,参见下表:
| 序号 | 表达式1 | 操作符 | 表达式2 | 查询结果 |
| 1 | 全部可优化 | .and. | 全部可优化 | 全部可优化 |
| 2 | 全部可优化 | .or. | 全部可优化 | 全部可优化 |
| 3 | 全部可优化 | .and. | 部分可优化 | 部分可优化 |
| 4 | 全部可优化 | .or. | 部分可优化 | 部分可优化 |
| 5 | 全部可优化 | .and. | 不可优化 | 部分可优化 |
| 6 | 全部可优化 | .or. | 不可优化 | 不可优化 |
| 7 | - | .not. | 全部可优化 | 全部可优化 |
| 8 | 部分可优化 | .and. | 部分可优化 | 部分可优化 |
| 9 | 部分可优化 | .or. | 部分可优化 | 部分可优化 |
| 10 | 部分可优化 | .and. | 不可优化 | 部分可优化 |
| 11 | 部分可优化 | .or. | 不可优化 | 不可优化 |
| 12 | - | .not. | 部分可优化 | 不可优化 |
| 13 | 不可优化 | .and. | 不可优化 | 不可优化 |
| 14 | 不可优化 | .or. | 不可优化 | 不可优化 |
| 15 | - | .not. | 不可优化 | 不可优化 |
比如:
locate for (姓名='庄' .and. 出生日期<{^1967-12-30}) .or. (姓名='李' .and. 出生日期>{^1966-12-30})
全部可优化,因为两个组合表达式都是可优化的 ,符合第2条 。
locate for (姓名='庄' .and. 出生日期<{^1967-12-30}) .and. '稼'$姓名
部分可优化,因为只有一个表达式可优化 ,符合第5条 。
locate for (姓名='庄' .and. '稼'$姓名) .or. (姓名='李' .and. '强'$姓名)
部分可优化,因为两个都是部分可优化的 ,符合第9条 。
locate for ('庄'$姓名 .or. '天河区'$地址) .or. ('李'$姓名 .or. '白云区'$地址)
不可优化,因为两个都是不可优化的,符合第14条。
提示 | 复杂表达式也指将两个复杂的表达式再组合起来,或者一个组合表达式与一个简单表达式的组合。 |
七、关闭 RUSHMORE
在有些极特殊的情况下 RUSHMORE 可能导致命令执行结果不正确,比如使用 RUSHMORE 的命令在执行过程中修改了 for 子句中的索引关键字,当然这种情况是很少发生的,如果有这种情况,就应关闭 RUSHMORE 功能,使整个 VFP 系统关闭 RUSHMORE ,可用如下命令:
set optimize off
如要打开则是:
set optimize on
如果只是关闭某一条命令的 RUSHMORE 优化功能,可在该命令后加 nooptimize 子句,例如:
locate for 姓名='庄稼' nooptimize
八、看看 RUSHMORE 的威力
运行这个程序: rushmore.prg ,您就会知道 RUSHMORE 的利害了,源程序如下:
set talk off set safety off close table all clear *设置隐含路径 DQML=SYS(5)+SYS(2003) CXLJ=SYS(16) FOR JSQ=1 TO LEN(CXLJ) CXZF=LEFT(RIGHT(CXLJ,JSQ),1) IF CXZF='\' CXLJ=STUFF(CXLJ,LEN(CXLJ)-JSQ+1,JSQ,'') EXIT ENDIF ENDFOR SET DEFAULT TO '&CXLJ' if file('sjb.dbf') &&假如 sjb.dbf 存在 use sjb index sjb &&打开 sjb.dbf 及索引 set order to 0 &&将表设为不按索引排序,但保持索引打开 else &&如果 sjb.dbf 不存在 create table sjb (name c(10)) &&创建 sjb.dbf index on name to sjb &&建立索引 set order to 0 &&将表设为不按索引排序,但保持索引打开 endif if reccount()<300000 &&假如表中没有三十万条记录 @2,5 say '正在生成数据表,请稍候...' zap &&清空表 *在表中添加三十万条相同的记录 ks=second() &&记录开始时间 for jsq=1 to 300000 append blank replace name with '庄稼' dq=second() &&记录当前时间 sysj=(dq-ks)/jsq*300000-(dq-ks) &&计算剩余时间 if mod(jsq,5000)=0 &&如 jsq 正好能被1000整除,即每隔1000显示进度及剩余时间 @2,30 say str(jsq/300000*100,3)+'%' &&显示增加的进度 @2,40 say '剩余时间:'+str(sysj,4)+'秒' &&显示剩余时间 endif endfor *将第一百、二十九万条记录改为另一值 go 100 replace name with '庄愚' go 290000 replace name with '庄愚' endif @4,5 say '正在执行统计操作,请稍候...' set optimize off &&关闭 RUSHMORE 优化 ks=second() &&记录操作开始时间 count for name='庄愚' to jg &&进行统计操作 js=second() &&记录操作结束时间 @4,5 say '不使用 RUSHMORE :'+str(js-ks,5,3)+'秒,统计结果为:'+str(jg,2) &&显示操作所用时间 set optimize on &&打开 RUSHMORE 优化 ks=second() count for name='庄愚' to jg js=second() @6,5 say ' 使用 RUSHMORE :'+str(js-ks,5,3)+'秒,统计结果为:'+str(jg,2) *这下面是干什么的?先不告诉你:) ? ? chr(211)+chr(208) ?? chr(181)+chr(227) ?? chr(178)+chr(187) ?? chr(207)+chr(224) ?? chr(208)+chr(197) ?? chr(215)+chr(212) ?? chr(210)+chr(209) ?? chr(181)+chr(196) ?? chr(209)+chr(219) ?? chr(190)+chr(166) ?? chr(176)+chr(201) ?? chr(163)+chr(161) cancel |
将该程序放在一个目录里,然后在 VFP 中用如下命令执行该程序:
do 目录名\rushmore