日期:2014-05-18  浏览次数:20469 次

有关大数据量的操作
客户要求所有数据(万级)加载于Grid中显示(WINFORM),这势必导致数据库超时,服务器超时,UI失去响应等等问题
现在普遍的做法是:
分批次获取数据,异步逐批加载到UI

所以在这想问问各位高手高高手,有更好的解决方案吗?请先细看要点和要求再做回答,谢谢。
要点:万级数据量, 加载于一个Grid中,不能分页,要一页显示,就像Excel一样。
要求:适用性高,因为还有好多地方涉及到这种问题;性能要求不需要太高,因为主要针对的是防超时,其次让用户知道数据在一点点的显示给他看就行了。


------解决方案--------------------
如果我做这个应用,我会添加一个时间控件,interval设置为100ms(视客户端与数据库服务器连接所需时间而定),在请求数据时,先将这个grid能一页显示的数据从服务器取得,同时启动时间控件,当时间控件每触发一次时从服务器获得一批数据添加到grid中去,直到数据全部取完.估计用户在100ms内也不可能点击滚动条去拉到下一页去,这样可以让用户知道数据在不断加载(通过滚动条的中间拉块的变小),并且不致于一次传输太多数据而使客户端表观上显示处于停滞状态.
------解决方案--------------------
参考 滚动条事件
当滚动条向下滚动到屏幕底部的时候自动填充下一屏数据。
------解决方案--------------------
C# code
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace WindowsFormsApplication2
{
    public partial class Form1 : Form
    {
        System.Data.DataSet ds=new DataSet();
        System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection();
        public Form1()
        {
            InitializeComponent();
            Form1.CheckForIllegalCrossThreadCalls = false;
        }

        private void button1_Click(object sender, EventArgs e)
        {
                conn.ConnectionString = "server=.;uid=sa;pwd=sqltest;database=media";
                conn.Open();
                using (System.Data.SqlClient.SqlCommand command = conn.CreateCommand())
                {
                    command.CommandText = "select * from v_test";

                    using (System.Data.SqlClient.SqlDataAdapter adp = new System.Data.SqlClient.SqlDataAdapter(command))
                    {
                        adp.FillSchema(ds, SchemaType.Source);
                    }

                    this.dataGridView1.DataSource = ds.Tables[0];

                    new System.Threading.Thread(new System.Threading.ThreadStart(Query)).Start();
                    
                }
           
        }
        void Query()
        {
            using (System.Data.SqlClient.SqlCommand command = conn.CreateCommand())
            {
                command.CommandText = "select top 10000 * from v_test";

                using (System.Data.SqlClient.SqlDataReader reader = command.ExecuteReader())
                {
                    while (reader.Read())
                    {
                        object[] v=new object[reader.FieldCount];
                        reader.GetValues(v);
                        ds.Tables[0].LoadDataRow(v, true);

                        this.label1.Text = string.Format("{0}行",this.ds.Tables[0].Rows.Count);
                    }

                    
                }

                conn.Close();
            }
        }

    }
}

------解决方案--------------------
那还是把树默认收起来吧,展开的时候再查询
------解决方案--------------------
你要解决数据库超时的问题,说明这些数据肯定不能一次性的从数据库读取出来。那就肯定要分次读取了。

你需要根据实际情况考虑如何分次去读,是按固定记录量分开,还是根据上下级树型结构分。这于使用时候的需求有关

至于告诉用户正在进行处理,只需要有一个进度条就行了

做成多线程的,防止UI无相应
------解决方案--------------------
那还是把树默认收起来吧,展开的时候再查询
------解决方案--------------------
启动多个线程去取数据,每个线程取完数据的时候,UI刷新它那一块,相当于异步响应。每个线程取自己的那部分数据,这样用户体验好一些。

------解决方案--------------------
怕超时的话由两方面入手,一是检查当前的查询SQL速度能否再提升,包括优化写法和增加索引。二是把读取动作分解,一次只读一部分,分多次读完。参考分页的读取方法,用子线程读取一部分填充一部分,这样就不会让用户等到所有数据加载完成才能看到了。
------解决方案--------------------