以文本方式查看主题

-  Foxtable(狐表)  (http://foxtable.com/bbs/index.asp)
--  专家坐堂  (http://foxtable.com/bbs/list.asp?boardid=2)
----  查询与赋值并存的效率问题请教  (http://foxtable.com/bbs/dispbbs.asp?boardid=2&id=194328)

--  作者:yankunhao
--  发布时间:2024/11/28 16:13:00
--  查询与赋值并存的效率问题请教

问题:我有一个【A】表,其中有5列数据是需要动态地从【规格明细】表中查询到【part_no】列一样的行,将【规格明细】表中相关的列值在表【A】中显示,目前我用像下面这样的代码方案处理,发现如果【A】表数据少时会很快就可以显示,但如果A】表数据中的数据多时(几千到万以上)就显得比较慢,请问有没更好的方案处理?

【A】表的AfterLoad事件代码:

Dim drs1 As List(of DataRow) = e.DataTable.Select("[part_no] is not null")
If drs1.Count > 0 Then
    For Each dr2 As DataRow In drs1
        
      
         Dim dr1 As DataRow = DataTables("规格明细").SQLFind("part_no = \'" & dr2("part_no") & "\'")

        
        If dr1 IsNot Nothing Then
            
            dr2("产品编码")=dr1("item_no")
            dr2("产品类别")=dr1("type_name")
            dr2("产品名称")=dr1("part_name")
            dr2("产品规格")=dr1("part_spec")
            dr2("工程BOM单据状态")=dr1("sheet_sta")
        Else
            dr2("产品编码")=Nothing
            dr2("产品类别")=Nothing
            dr2("产品名称")=Nothing
            dr2("产品规格")=Nothing
            dr2("工程BOM单据状态")=Nothing
        End If
        
    Next
End If


--  作者:有点蓝
--  发布时间:2024/11/28 16:16:00
--  
为什么不在平时录入的时候就引用数据呢,比如:http://www.foxtable.com/webhelp/topics/1453.htm,录一行就查一行。

一次性查几万行肯定慢的

--  作者:yankunhao
--  发布时间:2024/11/28 16:23:00
--  
有些之前已建立到基础数据或别的原因自动建立基础数据,且有时,一些基础数据是不相同的数据库建立或需要引用,而一些业务表之前没有将个别相同数据录入,有时在做查询统计时有需要引用别的表相关列内容显示,所以就有这个需求。


--  作者:yankunhao
--  发布时间:2024/11/28 16:30:00
--  

我看到说明文件中以下的说明,请问我上面的情况与说明中所说的条件一样吗?说明中说到(符合以下三个条件,会出现效率低下的情况),但我的情况好像不是同一表中的


出人意料的是,两段代码运行得都非常快,都在瞬间完成了。
那为什么第一段代码需要花费234秒?难道查询和赋值不能出现在同一个遍历语句中吗?
为此我改写了第一段代码,让查询和赋值分开进行,新的代码为:

Dim lst1 As New List(of DataRow)
Dim
lst2 AS New List(of DataRow)
For Each
dr As DataRow In DataTables("表A").DataRows
    If DataTables(
"表A").Find("第二列 = " & dr("第一列")) Is Nothing Then
        lst1
.Add(dr)
    Else

        lst2
.Add(dr)
    End If
Next
For Each
dr As DataRow In lst1
    dr
("第三列") = True
Next
For Each
dr As DataRow In lst2
    dr
("第三列") = False
Next

同样在数据为1万行,第三列无数据的时候,执行上述代码只花了0.8秒,比原来的234秒快了整整300倍,效率差距之大,令人瞠目。
原因应该找到了,为了验证我的想法,我打算对Compute方法进行测试,因为Compute在计算过程同样要进行查询。
于是我另外写了两段代码,这次不使用Find进行查询,而是使用Compute方法进行计算:

常规的代码,计算和赋值在同一个遍历语句:

Dim v As Double
For Each
dr As DataRow In DataTables("表A").DataRows
    v
= DataTables("表A").Compute("Count(第二列 )", "第二列 = " & dr("第一列"))
   
dr("第四列") = v

Next

估计效率更高的代码,计算和赋值分开进行:

Dim Dic As new Dictionary(of DataRow, Integer)
Dim
v As Double
For Each
dr As DataRow In DataTables("表A").DataRows
    v = DataTables("表A").Compute("Count(第二列 )", "第二列 = " & dr("第一列"))
    dic
.Add(dr, v
)
Next
For Each
dr As DataRow In dic.Keys
   
dr("第四列") = dic(dr)
Next

果不其然,经过测试,第二段比第一段同样快了整整300倍。

现在我总结一下,符合以下三个条件,会出现效率低下的情况:

1、用For语句遍历某个表。
2、遍历过程中会用Find或Select查询此表,或者用Compute方法统计此表。
3、遍历过程中会大量修改此表中某些行的值,被修改的行数越多,对于性能影响越大,如果被修改的行数很少,则几乎没有影响。

强调一下,上述三项中提到的表必须都是同一个表。
我们改写的代码之所以高效,是因为改写后的代码使得上述2、3项不再出现在同一个遍历语句中,而是在不同的遍历语句中出现。




--  作者:有点蓝
--  发布时间:2024/11/28 16:48:00
--  
那就试试上面的方法呗。
--  作者:yankunhao
--  发布时间:2024/11/28 17:10:00
--  
但上面的方法是只有引用一个列,如果有多个列值要更新,是要用多个字典?请问应该如何写这个代码比较好?


--  作者:有点蓝
--  发布时间:2024/11/28 17:17:00
--  
把多个列的数据合并到一个字符串不就行了,比如:"列1数据|列2 数据|..........."

使用的时候再拆分开