注册 登录
编程论坛 VFP论坛

请教一个问题,需要比较2个表中不同的记录,表过大怎么处理呢?

hjlali 发布于 2021-08-20 10:24, 2787 次点击
比较用的语句是:

SELECT * from ys1 where ALLTRIM(lxfs) NOT in  (select ALLTRIM(lxfs) from fs1 )

说明:因为ys1和fs1这2个表的数据都已经超过了26万条,处理起来非常非常慢,一晚上都比较不完,请问有什么更好的办法吗?

[此贴子已经被作者于2021-8-20 10:27编辑过]

31 回复
#2
XUFN2021-08-20 10:56
分二段试试
SELECT ALLTRIM(lxfs) AS MY_KEY from fs1 DIST NOCO INTO TABLE TEMP_KEY
SELECT * FROM ys1 where ALLTRIM(lxfs) NOT in(SELECT MY_KEY FROM TEMP_KEY)   
#3
吹水佬2021-08-20 11:37
26万条记录不算多吧,整个文件有多大?
#4
mywisdom882021-08-20 12:24
以下是引用hjlali在2021-8-20 10:24:54的发言:

比较用的语句是:
SELECT * from ys1 where ALLTRIM(lxfs) NOT in  (select ALLTRIM(lxfs) from fs1 )
说明:因为ys1和fs1这2个表的数据都已经超过了26万条,处理起来非常非常慢,一晚上都比较不完,请问有什么更好的办法吗?

你表有多少字段,是不是电脑原因,换电脑看看,同时,只用少量字段来测试,看是不是,时间少了。

SELECT ALLTRIM(lxfs) lxfs from ys1 where lxfs NOT in  (select ALLTRIM(lxfs) lxfs from fs1 )
#5
hjlali2021-08-20 12:45
以下是引用mywisdom88在2021-8-20 12:24:33的发言:


你表有多少字段,是不是电脑原因,换电脑看看,同时,只用少量字段来测试,看是不是,时间少了。

SELECT ALLTRIM(lxfs) lxfs from ys1 where lxfs NOT in  (select ALLTRIM(lxfs) lxfs from fs1 )

字段不多,一个fs表包含(lxfs,zt)两个字段,大小9M多,ys表包括(lxfs,xm,dw)三个字段,大小46M多,运行一次根本看不到进度。
只有本站会员才能查看附件,请 登录
#6
hjlali2021-08-20 12:57
以下是引用吹水佬在2021-8-20 11:37:13的发言:

26万条记录不算多吧,整个文件有多大?

两个表,一个9M多,一个46M多
#7
wengjl2021-08-20 13:00
换好一点的电脑吧!

我的数据量比你大,字段数比你多,一般都是几分钟的事儿
#8
sdta2021-08-20 13:09
用数据说话
#9
hjlali2021-08-20 13:17
以下是引用XUFN在2021-8-20 10:56:40的发言:

分二段试试
SELECT ALLTRIM(lxfs) AS MY_KEY from fs1 DIST NOCO INTO TABLE TEMP_KEY
SELECT * FROM ys1 where ALLTRIM(lxfs) NOT in(SELECT MY_KEY FROM TEMP_KEY)   

[b]你这个方法可行,速度比我这个快太多了。查出来7条lxfs(联系方式)不同的记录,不过语句还是有点请教的地方:
dist noco 这个语句是什么意思?求教下!


[color=#000066][此贴子已经被作者于2021-8-20 19:11编辑过]

#10
hjlali2021-08-20 13:31
以下是引用sdta在2021-8-20 13:09:35的发言:

用数据说话

数据涉及到敏感信息,不好提供,不好意思。意思我应该表述的比较清楚了
#11
hjlali2021-08-20 13:31
以下是引用mywisdom88在2021-8-20 12:24:33的发言:


你表有多少字段,是不是电脑原因,换电脑看看,同时,只用少量字段来测试,看是不是,时间少了。

SELECT ALLTRIM(lxfs) lxfs from ys1 where lxfs NOT in  (select ALLTRIM(lxfs) lxfs from fs1 )


不是电脑的问题,我电脑配置不算差,I7-8550的cpu,好像跟函数有关系,用了alltrim函数后速度大打折扣。
#12
吹水佬2021-08-20 14:51
示例
只有本站会员才能查看附件,请 登录

程序代码:
CREATE CURSOR ys1 (lxfs C(10))
INSERT INTO ys1 VALUES ("1001")
INSERT INTO ys1 VALUES ("1002")
INSERT INTO ys1 VALUES ("1003")
INSERT INTO ys1 VALUES ("1004")
CREATE CURSOR fs1 (lxfs C(10))
INSERT INTO fs1 VALUES ("1001")
INSERT INTO fs1 VALUES ("1003")
INSERT INTO fs1 VALUES ("1005")
INSERT INTO fs1 VALUES ("1006")

SELECT ys1
INDEX on lxfs TAG tag_ys1
SELECT fs1
INDEX on lxfs TAG tag_fs1

? "ys1 NOT IN fs1"
SELECT ys1
SET RELATION TO lxfs INTO "fs1"
LIST FOR !FOUND("fs1")
SET RELATION TO

? "fs1 NOT IN ys1"
SELECT fs1
SET RELATION TO lxfs INTO "ys1"
LIST FOR !FOUND("ys1")
SET RELATION TO
#13
xuminxz2021-08-20 16:59
先复制一个全的,用delete in (sele ...from   )试试。或者用
SELECT ys1.*,fs1.lxfs as lxfsb from ys1 left join fs1 on ys1.lxfs=fs1.lxfs into table tb1
dele for isnull(lxfsb)

[此贴子已经被作者于2021-8-20 17:04编辑过]

#14
hjlali2021-08-20 19:04
以下是引用xuminxz在2021-8-20 16:59:30的发言:

先复制一个全的,用delete in (sele ...from   )试试。或者用
SELECT ys1.*,fs1.lxfs as lxfsb from ys1 left join fs1 on ys1.lxfs=fs1.lxfs into table tb1
dele for isnull(lxfsb)

好像不能用join,join的原理有点不适合这个场景,在VFP里join出来的结果很多重复结果。
#15
hjlali2021-08-20 19:06
以下是引用吹水佬在2021-8-20 14:51:06的发言:

示例

CREATE CURSOR ys1 (lxfs C(10))
INSERT INTO ys1 VALUES ("1001")
INSERT INTO ys1 VALUES ("1002")
INSERT INTO ys1 VALUES ("1003")
INSERT INTO ys1 VALUES ("1004")
CREATE CURSOR fs1 (lxfs C(10))
INSERT INTO fs1 VALUES ("1001")
INSERT INTO fs1 VALUES ("1003")
INSERT INTO fs1 VALUES ("1005")
INSERT INTO fs1 VALUES ("1006")

SELECT ys1
INDEX on lxfs TAG tag_ys1
SELECT fs1
INDEX on lxfs TAG tag_fs1

? "ys1 NOT IN fs1"
SELECT ys1
SET RELATION TO lxfs INTO "fs1"
LIST FOR !FOUND("fs1")
SET RELATION TO

? "fs1 NOT IN ys1"
SELECT fs1
SET RELATION TO lxfs INTO "ys1"
LIST FOR !FOUND("ys1")
SET RELATION TO

谢谢你,你这个方法看起来更高阶一点。目前来看,我原来的语句语法是没有问题的,按照2楼的办法,分两段执行也就几秒钟就可以出来结果。
经过比较,主要是用了alltrim函数拖慢了速度,如果能有一条命令快速出结果的办法当然更好了。



[此贴子已经被作者于2021-8-20 19:08编辑过]

#16
hjlali2021-08-20 19:10
以下是引用xuminxz在2021-8-20 16:59:30的发言:

先复制一个全的,用delete in (sele ...from   )试试。或者用
SELECT ys1.*,fs1.lxfs as lxfsb from ys1 left join fs1 on ys1.lxfs=fs1.lxfs into table tb1
dele for isnull(lxfsb)

2楼的办法可以,出结果几秒钟。
#17
吹水佬2021-08-20 20:38
以下是引用hjlali在2021-8-20 19:06:21的发言:


谢谢你,你这个方法看起来更高阶一点。目前来看,我原来的语句语法是没有问题的,按照2楼的办法,分两段执行也就几秒钟就可以出来结果。
经过比较,主要是用了alltrim函数拖慢了速度,如果能有一条命令快速出结果的办法当然更好了。

对比测试一下,30W条记录
程序代码:
** 测试数据
CREATE CURSOR ys1 (lxfs C(10))
FOR i=1 TO 300000
    INSERT INTO ys1 VALUES (PADL(i,7,"0"))
ENDFOR
CREATE CURSOR fs1 (lxfs C(10))
APPEND FROM DBF("ys1")
SELECT ys1
GO TOP
REPLACE lxfs WITH "ys1_000001"
GO BOTTOM
REPLACE lxfs WITH "ys1_100000"

t = SECONDS()
SELECT ALLTRIM(lxfs) AS MY_KEY from fs1 DIST NOCO INTO TABLE TEMP_KEY
SELECT * FROM ys1 where ALLTRIM(lxfs) NOT in(SELECT MY_KEY FROM TEMP_KEY) NOWAIT   
?SECONDS()-t && 5.5s

** 去掉ALLTRIM
t = SECONDS()
SELECT lxfs AS MY_KEY from fs1 DIST NOCO INTO TABLE TEMP_KEY
SELECT * FROM ys1 where lxfs NOT in(SELECT MY_KEY FROM TEMP_KEY) NOWAIT   
?SECONDS()-t && 5.0s

t = SECONDS()
SELECT fs1
INDEX on lxfs TAG tag_fs1
SELECT ys1
SET RELATION TO lxfs INTO "fs1"
COPY TO tmp FOR !FOUND("fs1")
SET RELATION TO
?SECONDS()-t && 3.5s
SELECT * FROM tmp NOWAIT
#18
hjlali2021-08-20 20:41
以下是引用mywisdom88在2021-8-20 12:24:33的发言:


你表有多少字段,是不是电脑原因,换电脑看看,同时,只用少量字段来测试,看是不是,时间少了。

SELECT ALLTRIM(lxfs) lxfs from ys1 where lxfs NOT in  (select ALLTRIM(lxfs) lxfs from fs1 )


根据经验,是子句不能包含alltrim()函数,否则执行非常慢,会卡死
#19
hjlali2021-08-20 21:01
以下是引用吹水佬在2021-8-20 20:38:17的发言:


对比测试一下,30W条记录
** 测试数据
CREATE CURSOR ys1 (lxfs C(10))
FOR i=1 TO 300000
    INSERT INTO ys1 VALUES (PADL(i,7,"0"))
ENDFOR
CREATE CURSOR fs1 (lxfs C(10))
APPEND FROM DBF("ys1")
SELECT ys1
GO TOP
REPLACE lxfs WITH "ys1_000001"
GO BOTTOM
REPLACE lxfs WITH "ys1_100000"

t = SECONDS()
SELECT ALLTRIM(lxfs) AS MY_KEY from fs1 DIST NOCO INTO TABLE TEMP_KEY
SELECT * FROM ys1 where ALLTRIM(lxfs) NOT in(SELECT MY_KEY FROM TEMP_KEY) NOWAIT   
?SECONDS()-t && 5.5s

** 去掉ALLTRIM
t = SECONDS()
SELECT lxfs AS MY_KEY from fs1 DIST NOCO INTO TABLE TEMP_KEY
SELECT * FROM ys1 where lxfs NOT in(SELECT MY_KEY FROM TEMP_KEY) NOWAIT   
?SECONDS()-t && 5.0s

t = SECONDS()
SELECT fs1
INDEX on lxfs TAG tag_fs1
SELECT ys1
SET RELATION TO lxfs INTO "fs1"
COPY TO tmp FOR !FOUND("fs1")
SET RELATION TO
?SECONDS()-t && 3.5s
SELECT * FROM tmp NOWAIT

谢谢你的专业指导!!确实不是数据量的问题,是语法有问题,where in()括号里面的子句不能包含alltrim,否则执行不下去。我不知道你用的什么数据测试的,我把对比数据脱敏了,你实测下看看。希望还有人能给出更多的方案!
只有本站会员才能查看附件,请 登录


[此贴子已经被作者于2021-8-20 21:21编辑过]

#20
hjlali2021-08-20 21:03
以下是引用sdta在2021-8-20 13:09:35的发言:

用数据说话

数据已上传,已脱敏,可以试试看。

只有本站会员才能查看附件,请 登录
#21
吹水佬2021-08-20 21:07
应该是一句快点
SELECT * from ys1 WHERE lxfs NOT in (select lxfs from fs1 )
#22
hjlali2021-08-20 21:25
以下是引用吹水佬在2021-8-20 21:07:01的发言:

应该是一句快点
SELECT * from ys1 WHERE lxfs NOT in (select lxfs from fs1 )

如果没有空格、制表符等特殊字符的时候,这样执行是最好的,但实际上可能会不准。
我刚才执行语句“SELECT * from fs where ALLTRIM(lxfs) NOT in  (SELECT lxfs from ys )”
发现个奇葩的现象,where lxfs 这里加了alltrim函数和不加这个函数,比较出来的结果居然差了一个记录,这个差的记录就是一个有+86,一个没有,不知道是怎么回事,没搞懂VFP里面where in语句是怎么个运行原理。贴图如下:

只有本站会员才能查看附件,请 登录
只有本站会员才能查看附件,请 登录


只有本站会员才能查看附件,请 登录
只有本站会员才能查看附件,请 登录


[此贴子已经被作者于2021-8-20 21:41编辑过]

#23
吹水佬2021-08-20 21:44
回复 22楼 hjlali
如果只求有效的数据,肯定要先清理无效的数据。
制表符也有,数据是从其他地方批量导入的吧,最好在数据导入时就严格处理好。
有或无ALLTRIM结果可能不一样,看看有差别的数据记录有什么异常。

#24
sdta2021-08-20 22:03
有ALLTRIM()函数,速度肯定慢,模拟数据与真实数据还是有差别的,字段数的多少及记录数的多少对时间都是有影响的。
#25
sdta2021-08-20 22:05
字段名及类型相同,字段宽度不同,对时间也是有影响的。
#26
hjlali2021-08-20 22:35
以下是引用吹水佬在2021-8-20 21:44:34的发言:

如果只求有效的数据,肯定要先清理无效的数据。
制表符也有,数据是从其他地方批量导入的吧,最好在数据导入时就严格处理好。
有或无ALLTRIM结果可能不一样,看看有差别的数据记录有什么异常。

请问下VF里的  字段lxfs where in ()语句中,lxfs的值与in()里面lxfs的值对比的时候是精确对比还是包含关系对比?我感觉像是包含关系一样的。
#27
hjlali2021-08-20 22:36
以下是引用sdta在2021-8-20 22:03:26的发言:

有ALLTRIM()函数,速度肯定慢,模拟数据与真实数据还是有差别的,字段数的多少及记录数的多少对时间都是有影响的。

是的,要考虑的因素确实还挺多的,以前少量数据不觉得。
另外请问下VF里的  字段lxfs where in ()语句中,lxfs的值与in()里面lxfs的值对比的时候是精确对比还是包含关系对比?我感觉像是包含关系一样的。
#28
吹水佬2021-08-20 22:57
回复 26楼 hjlali
可以随便找几个数据试一下就清楚
#29
hjlali2021-08-21 12:57
以下是引用吹水佬在2021-8-20 22:57:01的发言:

可以随便找几个数据试一下就清楚

测试了一晚上,好像不是包含关系,但加函数和不加函数结果还是有差别,但是这个差别我没弄明白,单独开了个帖子,邀请你去探讨下,谢谢!!
帖子地址:https://bbs.bccn.net/thread-506598-1-1.html
#30
sdta2021-08-21 13:26
以下是引用hjlali在2021-8-21 12:57:08的发言:


测试了一晚上,好像不是包含关系,但加函数和不加函数结果还是有差别,但是这个差别我没弄明白,单独开了个帖子,邀请你去探讨下,谢谢!!
帖子地址:https://bbs.bccn.net/thread-506598-1-1.html

两个表lxfs字段宽度不同、内容不同造成的

[此贴子已经被作者于2021-8-21 13:28编辑过]

#31
sdta2021-08-21 13:35
以下是引用hjlali在2021-8-20 22:35:37的发言:


请问下VF里的  字段lxfs where in ()语句中,lxfs的值与in()里面lxfs的值对比的时候是精确对比还是包含关系对比?我感觉像是包含关系一样的。

测试结果不一定是包含关系,比较是按字段宽度的内容比较,如果(被)比较字段(如F1表的LXFS)用了ALLTRIM(),应该是包含关系

[此贴子已经被作者于2021-8-21 13:42编辑过]

#32
sdta2021-08-21 13:56
* 自己比较下两表相同字段的内容是否包含在另一个表中相同字段的内容中或者是否精确比较
CREATE CURSOR f1 (a1 c(10))
INSERT INTO f1 VALUES ("12345")

CREATE CURSOR f2 (a1 c(15))
INSERT INTO f2 VALUES ("123456")

SELECT * FROM f1 WHERE a1 NOT in (SELECT a1 FROM f2)
SELECT * FROM f1 WHERE ALLTRIM(a1) NOT in (SELECT a1 FROM f2)
SELECT * FROM f1 WHERE a1 NOT in (SELECT ALLTRIM(a1) FROM f2)
1