Вложенные FutureBuilder против вложенных вызовов для отложенной загрузки из базы данных - PullRequest
1 голос
/ 22 мая 2019

Мне нужно выбрать лучший подход между двумя подходами, которым я могу следовать.

У меня есть приложение 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 и извлечь из нее идентификатор отдела. Это легко, но после извлечения dep_id мне нужно сделать карту из этих идентификаторов, поэтому мне нужна информация из Department Таблица. полная информация для тех идентификаторов, которые я получил из Emplyee таблица находится внутри отдел таблица.

В каждой таблице тысячи строк.

У меня есть класс помощника базы данных для подключения к базе данных:

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_id из Таблица Employee (getDepartmentIds) и другую функцию, которая возвращает объект отдела (модель) для этого конкретного идентификатора (getDepartment). )

  2. Теперь мне нужно два FutureBuilder друг в друге, один для получения идентификаторов, а другой - для выбора модели отдела.

второй Один:

  1. Определите функцию, которая сначала получает идентификаторы, а затем внутри этой функции каждый идентификатор сопоставляется с моделью отдела. (getEmployeeDepartments)
  2. Так что мне нужен один FutureBuilder.

Какой из них лучше ?? я должен позволить FutureBuilders справиться с этим, или я должен оказать давление на dbHelper, чтобы помешать этому?

Если я использую первый подход, тогда я должен (насколько я могу представить!) Поставить второй будущий вызов (тот, который извлекает Department Объект (модель), основанный на его id (getDepartment)) для функции build, и рекомендуется не делать этого.

И проблема со вторым в том, что он делает много вложенных вызовов в dbHelper.

Я использовал ListView.builder для исполнения.

Я проверил оба с некоторыми данными, но не мог понять, какой из них лучше. Я думаю, это зависит как от флаттера, так и от sqlite (sqflite).

Какой из них лучше или есть какой-то лучший подход?

Ответы [ 2 ]

2 голосов
/ 23 мая 2019

Учитывая, что я не вижу слишком много кода в этом примере, я сделаю высокоуровневый ответ на ваши вопросы.

Оцените первый подход

  1. Сразу же появляется эта часть: «возвращает все dep_id из таблицы Employee»
  2. Я бы сказал, что, поскольку «вернуть все», как правило, никогда не является хорошим решением, особенно если вы упомянулив таблицах много строк.

Оценить второй подход

  1. Я не уверен, какая разница в производительности по сравнению с первымподход, кажется, также плохо по тем же причинам.Я думаю, что это просто меняет логику вашего пользовательского интерфейса, и это все.

Типичный подход к бесконечному списку

  1. Вы бы сделали запрос натаблица Employees с объединением с таблицей Departments .
  2. Вы бы реализовали разбиение на страницы на своем пользовательском интерфейсе и передавали свои значения в запрос с первого шага.
  3. На базовом уровне вам понадобятся следующие переменные: Take, Skip, HasMore
  4. Take: Количество # пунктов для запроса каждого запроса
  5. Пропустить: Количество элементов, которые нужно пропустить при следующем запросе, это будет размер количества элементов, которые вы в данный момент имеете в своем Списке в памяти для управления вашим пользовательским интерфейсом.
  6. HasMore: Вы можете установить это в ответе на каждый запрос, чтобы пользовательский интерфейс знал, есть ли еще элементы или нет.
  7. Когда вы прокручиваете список вниз, когда вы добираетесь до дна,вы будете запрашивать больше элементов.

Сначала выполните запрос, например: Take: 10, Skip: 0 Nextзапрос при достижении нижней части пользовательского интерфейса: принять: 10, пропустить: 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

Надеюсь, это помогает, я не совсем уверенчто вы пытаетесь сделать на самом деле - с точки зрения Кодекса.

1 голос
/ 23 мая 2019

Насколько я могу судить, вам нужно получить список сотрудников с соответствующей информацией, включая отдел.

Если это так, то это специально для INNER JOIN.Примерно так:

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

(хотя вы можете перепроверить это, мой SQL немного ржавый).

Это сделает то, что вам нужно, за один шаг.Тем не менее, все еще остается вопрос о том, что вы спрашиваете: «Более эффективно делать много маленьких запросов или один большой, и каковы последствия для производительности».

Ответ на этот вопроснемного специфичен для Флаттера.Когда вы делаете запрос с помощью SQFLITE, происходит то, что он обрабатывает все, что вы ему передали, отправляет его в java / objc и, возможно, выполняет больше обработки и передает обработку фоновому потоку, который затем вызывает библиотеку SQLITE, котораявыполняет дополнительную обработку, чтобы понять запрос, затем фактически читает данные на диске для выполнения операции, затем возвращается обратно на уровень java / objc, который передает ответ потоку пользовательского интерфейса, который, в свою очередь, отвечает обратно на dart.

Если это не звучит особенно эффективно, это потому, что это не = D.Если вы делаете это несколько раз (или даже несколько сотен), это, вероятно, хорошо, но если вы получаете тысячи, как вы заявляете, это может начать замедляться.

Альтернатива, которую вы предложили,сделать один большой запрос.Вы будете знать лучше меня, мудро ли это;если это пара тысяч, а не всегда пара тысяч, и возвращаемые вами данные всегда будут относительно небольшими (т. е. всего 10-20 символов имени и названия отдела), то вы скажете (20 + 20) * 2000 = 8000b = 80 КБ данных.Даже если вы предполагаете, что накладные расходы удвоят этот размер, 160 КБ данных не должно быть достаточно, чтобы потревожить любой относительно свежий смартфон (ведь это намного меньше, чем любая отдельная фотография!).

Теперь, взяв некоторый доменконкретные знания, вы могли бы оптимизировать это.Например, если вы знаете, что количество отделов намного меньше, чем сотрудников (то есть <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, который выполняетфактические запросы, и ваш список будет вызывать его, чтобы получить данные.Это, вероятно, выходит за рамки этого вопроса.

...