You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

加载2000+条数据库记录卡顿,求快速加载及进度显示方案

优化建议:提升加载速度并实现进度条显示

一、先把加载速度提上来

  • 别用select *,只查实际需要的字段
    原SQL用select *会返回表中所有字段,但你代码里仅用到10个列,改成明确指定字段的SQL,能大幅减少数据库传输的数据量:
    Dim cmd As New OleDbCommand("select ID, storecode, check_date, check_num, check_name, check_memo, check_amount, date_release, date_deposit, status from tblstore ORDER by storecode, check_date, ID ASC", conn)
    
  • 放弃逐行添加,用DataAdapter批量加载
    你现在循环dr.Read然后逐行调用DataGridView1.Rows.Add,每加一行都会触发UI刷新,效率极低。换成OleDbDataAdapter把数据一次性加载到DataTable,再绑定到DataGridView,速度会快很多。
  • 暂停DataGridView的视觉刷新
    加载数据前先暂停控件布局,加载完再恢复,避免重复刷新界面拖慢速度:
    DataGridView1.SuspendLayout()
    ' 这里做数据绑定操作
    DataGridView1.ResumeLayout()
    
  • 用Using管资源,别手动Dispose
    数据库连接、命令、适配器这些资源,用Using语句自动释放,既安全又不用手动写Dispose,还能确保连接及时关闭,不会占着资源。

二、正确实现进度条,别搞不安全的跨线程操作

你之前设Control.CheckForIllegalCrossThreadCalls = False是偷懒的做法,很容易出问题,用BackgroundWorker自带的事件机制就能安全更新UI:

  1. 先开BackgroundWorker的进度报告开关
    在设计器里把BackgroundWorker的WorkerReportsProgress和WorkerSupportsCancellation勾上,或者代码里设置:
    BackgroundWorker1.WorkerReportsProgress = True
    BackgroundWorker1.WorkerSupportsCancellation = True
    
  2. 在DoWork里加载数据并报告进度
    先查总记录数,然后在填充数据的时候实时计算进度,用ReportProgress发出去:
    Private Sub BackgroundWorker1_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
        Dim dt As New DataTable()
        Try
            ' 用Using包裹连接,自动释放
            Using conn As New OleDbConnection("你的数据库连接字符串")
                conn.Open()
                ' 先拿总记录数,用来算进度百分比
                Dim countCmd As New OleDbCommand("select count(*) from tblstore", conn)
                Dim totalCount As Integer = CInt(countCmd.ExecuteScalar())
                ' 查数据的SQL用刚才优化过的
                Dim cmd As New OleDbCommand("select ID, storecode, check_date, check_num, check_name, check_memo, check_amount, date_release, date_deposit, status from tblstore ORDER by storecode, check_date, ID ASC", conn)
                Using adapter As New OleDbDataAdapter(cmd)
                    ' 绑定填充进度事件,实时报告进度
                    AddHandler adapter.FillProgress, Sub(s, args)
                                                        Dim progress = CInt((args.RecordsLoaded / totalCount) * 100)
                                                        BackgroundWorker1.ReportProgress(progress)
                                                    End Sub
                    adapter.Fill(dt)
                End Using
            End Using
            e.Result = dt ' 把加载好的DataTable传给完成事件
        Catch ex As Exception
            e.Result = ex ' 把异常信息传回去
        End Try
    End Sub
    
  3. ProgressChanged事件里更新进度条
    这里是安全的UI线程,可以直接操作进度条:
    Private Sub BackgroundWorker1_ProgressChanged(sender As Object, e As System.ComponentModel.ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
        ProgressBar1.Value = e.ProgressPercentage
    End Sub
    
  4. RunWorkerCompleted事件里绑定数据
    数据加载完后,在这个事件里把DataTable绑定到DataGridView,同时处理异常:
    Private Sub BackgroundWorker1_RunWorkerCompleted(sender As Object, e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
        If e.Result IsNot Nothing Then
            If TypeOf e.Result Is Exception Then
                MsgBox(CType(e.Result, Exception).Message)
            Else
                DataGridView1.SuspendLayout()
                DataGridView1.DataSource = CType(e.Result, DataTable)
                DataGridView1.ResumeLayout()
            End If
        End If
        ProgressBar1.Value = 0 ' 加载完重置进度条
    End Sub
    
  5. 修正窗体加载事件
    删掉那个不安全的Control.CheckForIllegalCrossThreadCalls = False,直接启动BackgroundWorker就行:
    Private Sub manageCheck_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        BackgroundWorker1.RunWorkerAsync()
    End Sub
    

三、额外的小优化

  • 关掉DataGridView的自动列生成
    提前在设计器里把DataGridView的列配置好,设置每一列的DataPropertyName对应数据库字段,然后把AutoGenerateColumns设为False,避免自动生成列的开销:
    DataGridView1.AutoGenerateColumns = False
    ' 比如:
    IDColumn.DataPropertyName = "ID"
    StoreCodeColumn.DataPropertyName = "storecode"
    ' 其他列同理配置
    
  • 数据量再大就开虚拟模式
    如果以后数据超过几万条,可以把DataGridView的VirtualMode设为True,按需加载数据,能进一步降低内存占用和加载时间。

内容的提问来源于stack exchange,提问作者Nnek Lecxe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 21:05:17