【问题标题】:C# SQLiteDataAdapter Fill Method is slowC# SQLiteDataAdapter 填充方法很慢
【发布时间】:2017-09-25 11:31:19
【问题描述】:

问题域是我有一个大约 90000 行和 6 列的 db 文件。我得到了一个 Select 查询,在其中我得到了我需要的所有行和列,并且工作正常。现在是我用这些记录填充 DataTable 的事情。我使用 SQliteDataAdapter 填充方法执行此操作,这大约需要 1.3 秒,之后我用这些数据填充我的 ObservableCollection(

private void GetSelectedMaterial()
    {
        DataTable dtMaterial = new DataTable();
        materialColl.Clear(); // Clearing ObservableCollection

        Trace.WriteLine("GetSelectedMaterial TS " + DateTime.Now + DateTime.Now.Millisecond);
        using (SQLiteConnection connection = new SQLiteConnection(dbConnection))
        using (SQLiteCommand cmd = connection.CreateCommand())
        {
            connection.Open();

            query = "SELECT * FROM Tbl_Materialliste LEFT JOIN(SELECT * FROM Tbl_Besitzt k WHERE k.TechnikID = '" + teTechnikID + "') as k ON k.MaterialID = Tbl_Materialliste.MaterialID";

            dataAdapter = new SQLiteDataAdapter(query, connection);
            Trace.WriteLine("query: " + DateTime.Now + DateTime.Now.Millisecond);

            dtMaterial.Columns.Add("Checked", typeof(bool));
            Trace.WriteLine("here comes the fill: " + DateTime.Now + DateTime.Now.Millisecond);
            dataAdapter.Fill(dtMaterial);

            Trace.WriteLine("Checkbox: " + DateTime.Now + DateTime.Now.Millisecond);
            DetermineCheckBox(dtMaterial, teTechnikID, 8);
            Trace.WriteLine("SQL TS: " + DateTime.Now + DateTime.Now.Millisecond);
        }

        FillMaterialColl(dtMaterial);
    }

    private void FillMaterialColl(DataTable dtMaterial)
    {
        foreach (DataRow dr in dtMaterial.Rows)
        {
            Material mat = new Material();

            mat.isChecked = (bool)dr.ItemArray[0];
            mat.materialID = (string)dr.ItemArray[1];
            mat.materialkurztext = (string)dr.ItemArray[2];
            mat.herstellername = (string)dr.ItemArray[3];
            mat.herArtikenummer = (string)dr.ItemArray[4];
            mat.dokument = (string)dr.ItemArray[5];
            mat.substMaterial = (string)dr.ItemArray[6];

            materialColl.Add(mat);
        }
    }

我知道 ObservableCollections 会消耗性能,但有没有其他方法可以做到这一点?有人说要使用 DataReader 而不是 DataAdapter 但 DataAdapter 应该使用 DataReader 所以我认为性能没有提高。所以主要问题是这个过程需要很长时间,如果显示新材料大约需要 3-4 秒,用户体验也不是很好。..

编辑 所以我的数据库设计来了:

Tbl_Material 和 Tbl_Technik 之间是多对多的关系 我的 Select 查询为我提供了来自 Tbl_Material (~90k) 的所有条目,此外还有来自 Tbl_Besitzt 的那些列,我可以在其中找到 technikID 这样我就可以过滤(对于复选框)哪些条目属于我的 MaterialID 在我的数据库文件中,来自 Tbl_Materialliste 的 MaterialId 是一个 PK,也是来自 Tbl_Technik 的 TechnikID - 并不是你想知道设计图像,我没有将它们放入模型中。..

非常感谢!

【问题讨论】:

  • 是的,没错,但如果我在没有背景线程的情况下执行此操作,它不会改变...我将编辑我的代码,以便不需要线程...任何其他帮助想法?

标签: c# wpf sqlite observablecollection


【解决方案1】:

如果不了解数据库的架构和设计,就很难调查数据库的性能问题。在您的 SQL 查询中,有一个 join 表达式。您需要确保对相应的数据字段进行索引,以使连接操作快速。这也取决于两个表的数据大小。

为了加快搜索结果的显示速度,您应该避免在ObservableCollection<T> 中逐项添加它们。这是因为每次添加新项目时,绑定引擎都会将此项目传输到 DataGrid,从而导致网格执行显示记录所需的所有操作。

如果你真的不需要集合是可观察的(例如,你不会在视图中添加或删除任何项目),那么只需将其设置为 IEnumerable<T>

public IEnumerable<Material> Materials
{
    get { return this.materials; }
    private set
    {
         // Using the PRISM-like implementation of INotifyPropertyChanged here
         // Change this to yours
         this.SetProperty(ref this.materials, value);
    }
}

在你的方法中,创建一个本地List&lt;Material&gt;,填充它,然后暴露给视图:

List<Material> materials = new List<Material>();
// fill the list here
// ...
// finally, assign the result to your property causing the binding to do the job once
this.Materials = materials;

如果您需要 ObservableCollection&lt;T&gt;,您也可以使用相同的技巧 - 创建一个本地副本,填充它,最后公开。

如果这没有帮助,您应该尝试使用 UI 虚拟化。这是一个比较大的话题,但是网上有很多资料。

【讨论】:

  • 我按照您描述的方式更改了它,现在填充列表大约需要 250 毫秒!非常感谢!我会编辑我的帖子,这样你就可以看到我的数据库设计,也许你可以看看?
猜你喜欢
  • 2011-02-12
  • 2010-10-28
  • 1970-01-01
  • 2020-04-17
  • 2016-06-28
  • 2011-11-27
  • 1970-01-01
  • 1970-01-01
  • 2011-02-12
相关资源
最近更新 更多