1

我需要在我可以遵循的两种方法之间选择最佳方法。

我有一个用于保存数据的 Flutter 应用程序sqflite,在数据库中我有两个表:

员工:

+-------------+-----------------+------+
| employee_id | employee_name   |dep_id|
+-------------+-----------------+------+
|     e12     | Ada Lovelace    | dep1 |
+-------------+-----------------+------+
|     e22     | Albert Einstein | dep2 |
+-------------+-----------------+------+
|     e82     | Grace Hopper    | dep3 |
+-------------+-----------------+------+

SQL:

CREATE TABLE Employee(
    employee_id TEXT NOT NULL PRIMARY KEY,
    employee_name TEXT NOT NULL ,
    dep_id TEXT,
    FOREIGN KEY(dep_id) REFERENCES Department(dep_id)
    ON DELETE SET NULL
);

部门:

+--------+-----------+-------+
| dep_id | dep_title |dep_num|
+--------+-----------+-------+
| dep1   | Math      | dep1  |
+--------+-----------+-------+
| dep2   | Physics   | dep2  |
+--------+-----------+-------+
| dep3   | Computer  | dep3  |
+--------+-----------+-------+

SQL:

CREATE TABLE Department(
    dep_id TEXT NOT NULL PRIMARY KEY,
    dep_title TEXT NOT NULL ,
    dep_num INTEGER,
);

我需要显示一个ListGrid存储在Employee表中的部门。我应该查看Employee表并从中获取部门 id,这很容易,但是在获取之后dep_id我需要从这些 id 中制作一张卡片,所以我需要Department表中的信息。我从Emplyee表中获取的那些 id 的完整信息在Department表中。

每个表中有数千行。

我有一个数据库助手类来连接到数据库:

DbHelper是这样的:

Future<List<String>> getDepartmentIds() async{
    'fetch all dep_id from Employee table'
}

Future<Department> getDepartment(String id) async{
    'fetch Department from Department table for a specific id'
}

Future<List<Department>> getEmployeeDepartments() async{
    '''1.fetch all dep_id from Employee table
    2.for each id fetch Department records from Department table'''

    var ids = await getDepartmentIds();
    List<Departments> deps=[];
    ids.forEach((map) async {
        deps.add(await getDepartment(map['dep_id']));
      });
}

有两种方法:

第一:

  1. 在 dbhelper 中定义一个函数,该函数dep_idEmployee表中返回所有内容(getDepartmentIds以及另一个返回该特定 id 的部门对象(模型)的函数。(getDepartment

  2. 现在我需要两个FutureBuilder相互连接,一个用于获取 id,另一个用于获取部门模型。

第二个:

  1. 定义一个函数,首先获取 id,然后在该函数中,每个 id 都映射到部门模型。(getEmployeeDepartments
  2. 所以我需要一个FutureBuilder

哪一个更好??我应该让 FutureBuilders 处理它还是应该施加压力dbHelper来处理它?

如果我使用第一种方法,那么我必须(据我想象!)将第二个未来调用(基于它的 id( ) 获取DepartmentgetDepartment Object(model) 的调用)放在build函数上,建议不要这样做所以。

第二个的问题是它做了很多嵌套调用dbHelper

我用于ListView.builder表演。

我用一些数据检查了两者,但无法弄清楚哪个更好。我想这取决于颤振和 sqlite(sqflite)。

哪个更好或有更好的方法?

4

2 回答 2

3

鉴于我在此示例中没有看到太多代码,我将对您的问题进行高级别的回答。

评估方法一

  1. 马上这部分就突出了:“从 Employee 表返回所有 dep_id”
  2. 我会说从头开始,因为“全部归还”通常不是一个好的解决方案,特别是因为您提到您的表有很多行。

评估方法二

  1. 我不确定这与第一种方法相比在性能上有什么不同,出于同样的原因,这似乎也很糟糕。我认为这只是改变了你的 UI 逻辑。

典型的“无尽”列表方法

  1. 您将通过连接到Departments表来查询Employees表。
  2. 您将在您的 UI 上实现分页,并将您的值从第一步传递给查询。
  3. 在基本层面上,您将需要这些变量:Take、Skip、HasMore
  4. Take:请求每个查询的项目数
  5. 跳过:在下一个查询中要跳过的项目数,这将是您当前在内存中驱动 UI 的列表中的项目数的大小。
  6. HasMore:您可以在每个查询的响应中设置此项,以让 UI 知道是否还有更多项目。
  7. 当您向下滚动列表时,当您到达底部时,您将请求更多项目。

最初发出一个查询,例如:Take: 10, Skip: 0 当您点击 UI 底部时的下一个查询:Take: 10, Skip: 10 等等。

示例 sql 查询:

SELECT * 
FROM Employees E
   JOIN Departments D on D.id = E.dept_id
order by E.employee_name  
offset {SKIP#} rows
FETCH NEXT {TAKE#} rows only

希望这会有所帮助,我不完全确定您实际上要做什么 - 就代码而言。

于 2019-05-22T21:15:34.857 回答
1

据我所知,您要做的是获取包含相关信息(包括部门)的员工列表。

如果是这样,那么它就是为 INNER JOIN 量身定做的。像这样的东西:

SELECT Employee.*, Department.dep_id, Department.dep_title 
   FROM Employee INNER JOIN Department 
   ON Employee.dep_id = Department.dep_id;

(尽管您可能想仔细检查一下,我的 SQL 有点生疏)。

这将一步完成您需要的。但是,仍然存在您要问的问题,这似乎是“执行许多小请求还是执行一个大请求更有效,以及性能影响是什么”。

这个问题的答案有点特定于 Flutter。当您使用 SQFLITE 发出请求时会发生什么,它正在处理您传递给它的任何内容,将其发送到 java/objc 并可能进行更多处理并将处理推送到后台线程,然后调用 SQLITE 库做更多的处理来理解请求,然后实际读取磁盘上的数据进行操作,然后返回到 java/objc 层,该层将响应推送给 UI 线程,UI 线程依次响应回 dart。

如果这听起来不是特别有效,那是因为它不是 =D。如果你这样做几次(甚至几百次)可能没问题,但如果你按照你的说法进入数千次,它可能会开始放慢速度。

您提出的替代方案是做一个大请求。你会比我更清楚这是否明智;如果它是几千但只有几千,并且您返回的数据总是相对较小(即只有 10-20 个字符的名称和部门名称),那么您会说 (20+20 )*2000 = 8000b = 80kb 数据。即使您假设开销会增加一倍,160 kb 的数据也不应该足以让任何相对较新的智能手机感到困惑(毕竟这比任何一张照片都要小得多!)。

现在,利用一些特定领域的知识,您可以对其进行优化。例如,如果您知道部门的数量远小于员工数量(即 < 100 或其他),您可以跳过整个连接问题,并在此开始之前简单地请求所有部门并将其放入地图中(dep_id = > dep_title),然后一旦你请求了员工,你就可以简单地自己从 dep_id 到 dep_title 进行查找。这样,您的请求就不必一遍又一遍地包含 dep_title 。

话虽如此,您可能需要考虑分页员工查找,无论您是否使用联接。您可以通过一次请求 100 名员工(或任何数量)而不是整个批次来做到这一点 - 这样您就没有通过堆栈进行 1000 多次调用的开销,但您也没有大块一次全部在内存中的数据。

SELECT * FROM Employee
WHERE employee_name >= LastValue
ORDER BY employee_name
LIMIT 100;

不幸的是,这与颤振处理列表的方式不相符,因此您可能需要有类似“EmployeeDatabaseManager”之类的东西来执行实际请求,并且您的列表会调用它来获取数据。不过,这可能超出了这个问题的范围。

于 2019-05-22T21:54:54.303 回答