注册 登录
编程论坛 VFP论坛

SQL语句,where (字段值 Like %子串%) 或者 (atcc(子串, 字段值)>0),该如何尽量地Rushmore优化呢?

cssnet 发布于 2023-03-19 12:38, 2421 次点击
比方说:
update 地址汇总表 SET 已处理 = .t. , 联系地址 = strtran(联系地址, trim(地址更新表.旧串), trim(地址更新表.新串)) from 地址更新表 WHERE 联系地址 like "%"+trim(地址更新表.旧串)+"%" .and. ! 已处理
大意是,地址定期更新时,凡带有“向阳西路”的,统一更换为“爱麦斯西路”,“明水区”的,统一更换为“高新区”。“地址更新表.dbf”中保存对应表:

旧串, 新串
"向阳西路", "爱麦斯西路"
"明水区", "高新区"
...

where条件若为like、like()或者atcc(),当数据表较大,达到10W+甚至更多记录时,运行起来会狠慢。
索引“联系地址”、“旧串”等字段,好像并不管用。
24 回复
#2
sdta2023-03-19 15:31
REPLACE 命令不行吗
#3
cssnet2023-03-19 18:50
以下是引用sdta在2023-3-19 15:31:53的发言:
REPLACE 命令不行吗


replace也根本无任何速度优势啊,一样一样的:

select B
use 地址汇总表
select A
use 地址更新表
scan
    * select A
    lcOldStr = trim(A.旧串)
    lcNewStr = trim(A.新串)
    select B
    replace 已处理 with .t. , 联系地址 with strtran(联系地址, lcOldStr, lcNewStr) for atcc(lcOldStr, 联系地址)>0 .and. ! 已处理
endscan
#4
csyx2023-03-20 09:01
印象中只有左/右包含可以有效利用索引,这种全包含用不上
不过,把 已处理 放在 地址 like ... 前面显然没坏处

[此贴子已经被作者于2023-3-20 10:25编辑过]

#5
吹水佬2023-03-20 09:55
地址格式不规范有可能产生的结果。
地址应该是一个完整数据(具有唯一性),不能说A包含了XXX就是B的地址,这样就带有不确定性,这样修改的结果也有可能是不对的。
#6
csyx2023-03-20 10:16
区县,街道改名很常见,一个县区上千个单位,手工一个一个修改也不是不行,实际上ZF部门也是这么样做的,不然要那么些公务员干哈
#7
吹水佬2023-03-20 10:24
不要用其中含XXX新旧对照表,最好用完整的新旧地址对照表来修改,这样一次扫描对照就可以。
#8
吹水佬2023-03-20 10:28
新旧地址对照表应该也是人工生成,平时及时修改地址的应该也没多少功夫,主要是根据新旧地址对照表来修改总地址数据要准确高效。
#9
吹水佬2023-03-20 10:31
有地址编码库就更好,数据处理只认编码,地址文本只作显示用。
#10
倦猫19732023-03-20 18:17
如果(地址更新表.旧串)这个字段的值是唯一,恐怕再无任何办法。
如果(地址更新表.旧串)这个字段的值不唯一,那将有可能 join 出来一个超级大的结果集,也许这才是 Update 慢的主要原因。
#11
cssnet2023-03-21 10:09
以下是引用csyx在2023-3-20 09:01:04的发言:
把 已处理 放在 地址 like ... 前面显然没坏处


这一点确实我没想到,很具性价比的顺序调整建议!非常感谢!

以下是引用倦猫1973在2023-3-20 18:17:05的发言:
有可能 join 出来一个超级大的结果集,也许这才是 Update 慢的主要原因。


join这个关键词,振聋发聩,我得好好思考一下!非常感谢!

第一版实在太慢,确实“旧串”不唯一;不过后来无意中我也发觉到了,第二版重新做了一个unique旧串表,然而速度并未有实质性提升。
仍是巨慢。哪怕换一台最新i7电脑32G内存,也没多少改善,得到的印象,近乎是当年586/2G的速度。
#12
吹水佬2023-03-21 10:50
以下是引用cssnet在2023-3-19 18:50:15的发言:

replace也根本无任何速度优势啊,一样一样的:

replace 看什么状况,如下数据状态,对VFP来说应该是神速了。

CREATE CURSOR 地址汇总表 (地址 v(240))
INSERT INTO 地址汇总表 VALUES ("地址1")
INSERT INTO 地址汇总表 VALUES ("地址2")
INSERT INTO 地址汇总表 VALUES ("地址3")
INSERT INTO 地址汇总表 VALUES ("地址4")
INSERT INTO 地址汇总表 VALUES ("地址5")
CREATE CURSOR 地址更新表 (旧地址 v(240), 新地址 v(240))
INSERT INTO 地址更新表 VALUES ("地址1","地址111")
INSERT INTO 地址更新表 VALUES ("地址3","地址333")
INSERT INTO 地址更新表 VALUES ("地址5","地址555")
INDEX on 旧地址 TAG tag_地址
SELECT 地址汇总表
SET RELATION TO 地址 INTO "地址更新表"
REPLACE 地址 WITH 地址更新表.新地址 FOR FOUND("地址更新表")
SELECT * FROM 地址汇总表

用编码就更可靠准确
CREATE CURSOR 地址汇总表 (编码 c(6), 地址 v(240))
INSERT INTO 地址汇总表 VALUES ("100001","地址1")
INSERT INTO 地址汇总表 VALUES ("100002","地址2")
INSERT INTO 地址汇总表 VALUES ("100003","地址3")
INSERT INTO 地址汇总表 VALUES ("100004","地址4")
INSERT INTO 地址汇总表 VALUES ("100005","地址5")
CREATE CURSOR 地址更新表 (编码 c(6), 旧地址 v(240), 新地址 v(240))
INSERT INTO 地址更新表 VALUES ("100001","地址1","地址111")
INSERT INTO 地址更新表 VALUES ("100003","地址3","地址333")
INSERT INTO 地址更新表 VALUES ("100005","地址5","地址555")
INDEX on 编码 TAG tag_编码
SELECT 地址汇总表
SET RELATION TO 编码 INTO "地址更新表"
REPLACE 地址 WITH 地址更新表.新地址 FOR FOUND("地址更新表")
SELECT * FROM 地址汇总表
#13
mywisdom882023-03-21 23:59
又不是天天改的,慢一点没什么。
难道吃饱没事做,天天去改啊
#14
倦猫19732023-03-24 20:27
你改成 Select Count(1) from a,b Where 就知道了命中多少记录可以。

设A表地址串有行 a+c, a+b, a+c, a+d 共4行记录,设B表有行a,b,c,d,虽然B表不重复。但你这个 Where 产生的 join 结果会命中16行记录。
#15
瓜瓜19902023-03-24 21:12
对条件中的字段建索引
#16
cssnet2023-04-01 22:31
若不想费时费力去构造SQL语句,那么转用VFP的“土话”——用Replace替代——有时候确实是非常高效,非常优异的,速度快出不仅仅是一个量级,而是“指数级”!
#17
吹水佬2023-04-02 10:14
以下是引用cssnet在2023-4-1 22:31:47的发言:

若不想费时费力去构造SQL语句,那么转用VFP的“土话”——用Replace替代——有时候确实是非常高效,非常优异的,速度快出不仅仅是一个量级,而是“指数级”!

如果单打独斗 Replace 未必都会输给 SELECT - SQL、UPDATE - SQL,是“土枪”还是“洋炮”,有兴趣的可以测试一下。

#18
倦猫19732023-04-02 22:53
以下是引用吹水佬在2023-4-2 10:14:28的发言:


如果单打独斗 Replace 未必都会输给 SELECT - SQL、UPDATE - SQL,是“土枪”还是“洋炮”,有兴趣的可以测试一下。



不用试了,100% 被 SQL 秒,我都有案例了我只是实在懒得动,几分种变成几百毫秒。
要如何对数据转换才能发挥出 SQL 最大性能这需要稍微动一下心思,而且是不改原表结构也不改变结果输出的情况下,仅在运算时对数据行列转换。
#19
吹水佬2023-04-03 05:00
以下是引用倦猫1973在2023-4-2 22:53:46的发言:

不用试了,100% 被 SQL 秒,我都有案例了我只是实在懒得动,几分种变成几百毫秒。
要如何对数据转换才能发挥出 SQL 最大性能这需要稍微动一下心思,而且是不改原表结构也不改变结果输出的情况下,仅在运算时对数据行列转换。


说的是“未必都会”输。
案例也只能说明某种情况。
SQL命令只是集成化高,相对解释语言来说,命令集成化越高运行效率越高,所谓的“一句搞定”就是这意思。
但集成化越高灵活性就越低,SQL命令对一些“复杂度”较高的问题,效率就显得不那么高,甚至不好处理。
“100% 被 SQL 秒”,这个“100%”的说法是不是对这个问题的理解出偏了。
#20
倦猫19732023-04-03 07:58
replace 要想发挥出最高性能,表关系是少不了。
SQL 就亲民很多了,原则上是:宁可什么都不做都不可多建索引。直到程序跑不动了,再去想办法。


二者完全适合不一样的应用场景,理论上并没有 PK 的机会。
#21
吹水佬2023-04-03 08:52
以下是引用倦猫1973在2023-4-3 07:58:19的发言:

replace 要想发挥出最高性能,表关系是少不了。
SQL 就亲民很多了,原则上是:宁可什么都不做都不可多建索引。直到程序跑不动了,再去想办法。

二者完全适合不一样的应用场景,理论上并没有 PK 的机会。


看来似出偏了,什么事情都不能离开实际。
理论归理论,现实中有时还真的用“土炮”就可以,无必要动不动就用“洋枪”。

程序 = 数据结构 + 算法,就是最基本的。SQL亲民不等于万能,是吧?
至于“建索引”,这是优化“数据结构 + 算法”不可缺少的环节,难道认为SQL的高度集成与“索引”无关吗?那就太小看“索引”了。
VFP的索引还能自动维护,不知有无体验过?

说句不爱听的,不要动不动就PK这PK那,总是爱将同一问题的不同方面对立起来看待,对探讨问题毫无建设性。
用 VFP - SQL 或用 replace 有时都可以处理同一类数据事务的,“二者完全适合不一样的应用场景”就有点看低VFP“土炮”的能力。
至于DBF的应用来说,就算不用 VFP - SQL 也一样能处理得很好,难道会有说不可能的吗?

再说句爱笑的,真喜欢PK,那就与16楼的PK一下,让人见识一下什么是“真功夫”。





#22
cssnet2023-04-03 09:24
以下是引用吹水佬在2023-4-3 08:52:37的发言:

再说句爱笑的,真喜欢PK,那就与16楼的PK一下,让人见识一下什么是“真功夫”。


吹版在搞事情!
无辜躺枪,传说中的16楼,表示严重关切,严重不满!
没错儿,我老人家平时没别的嗜好,就喜欢吹吹水、抬抬杠。
然而也挑对手的。
不是一切场合皆有兴致参与掰扯的。
你们PK你们的,我老人家搬张板凳来,只负责吃瓜,不负责动口。
——我又不是君子。

#23
吹水佬2023-04-03 09:37
回复 22楼 cssnet
言重!
将事论事,对事不对人。
#24
吹水佬2023-04-03 10:00
以下是引用cssnet在2023-4-3 09:24:55的发言:

吹版在搞事情!

没错儿,我老人家平时没别的嗜好,就喜欢吹吹水、抬抬杠。

“吹水”我不差、“抬杠”你不弱,半斤八两。
#25
cssnet2023-04-03 10:31
讲真,因最初是从DBASE III起步,小时候熟悉的完全是xBase“土话”那一套,SQL的语法,若不是恰好读到章立民《应用实务篇》,还真不太了解。
后来当然知晓了SQL的强大。
心服口服。
只不过,在做单机版的软件时,选择用Replace还是Update,那几乎纯是个人喜好,好像看不出太大差别。
SQL语句写得不好时,可能还真的远不如索引+“土话”高效!
只因SQL需要很细致分析、优化,而“土话”几乎不用过脑,顺序写下来,程序就能飞速运转起来,并得出了所需结果。
当然,这么说,绝无企图挑战SQL高手的意思——只因VFP的土炮实在太过强悍,导致有时似乎无必要发射导弹去打蚊子。
我说,是吧?

1