Как настроить мета-таблицы, чтобы эффективно вставлять большие массивы данных?

82
9

Я работаю над проектом обследования и ищу лучший способ отслеживать данные ответа в реляционной базе данных. Скажем, в опросе записываются любимые блюда. Позже я добавлю дополнительные данные в новые продукты (калории). Я считаю, что я думаю, что таблицы должны выглядеть так:


люди


id | name
==================
1 | John
2 | Suzy
3 | Joe
4 | Laura
5 | Bob

<сильные > продукты


id  | food       | calories
============================
10 | spaghetti | 950
11 | meatloaf | 850
12 | tofu | 600
13 | cake | 550

выбор


**people_food**
------------------
1 | 10
2 | 11
3 | 12
4 | 13
5 | 10

Это позволяет мне использовать целые числа для связей между таблицами, что делает выполнение JOINs быстрым и не дает мне дублировать данные. Недостаток, я считаю, заключается в том, что до ввода новых данных я должен сначала выполнить поиск идентификатора в таблице food, чтобы убедиться, что добавленная вами еда еще не существует.


Это достаточно просто для небольшой базы данных, но что, если бы я решил, что я буду спрашивать людей о своих лучших 100 любимых блюдах, и этот опрос будет отправлен тысячам людей? Даже с индексом таблицы продуктов, что означает, что каждый раз, когда мы идем, чтобы вставить 100 вариантов, нам нужно запросить продукты, чтобы получить идентификаторы существующих продуктов. (Это означает 100 запросов?) Я думаю, что могу сделать что-то вроде:


foreach($response as $food)
{
$food_id = my_mysql_function('select id from foods where food = "spaghetti"');

if( ! $food_id ){
$food_id = my_mysql_function_return_query_id( "insert into foods (NULL, '$food')" );
}

my_mysql_function( "insert into people_foods ($person_id, $food_id)" );

}


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


Вопросы


С такой схемой, каков наиболее эффективный способ записи нового ответа и либо получить идентификатор для существующей еды, либо вставить пищу? Если я вставляю 100 продуктов, я обычно делаю что-то вроде:


$existing = my_mysql_function('select id, food from foods where food in ('.implode($response,',').')');
foreach($existing as $food){
my_mysql_function_return_query_id( "insert into people_foods ($person_id, '$food['id']')" );
unset($response[$food]);
}

foreach($response as $food){
//same code as above mentioned earlier in the question
}


Или, есть ли просто другая схема таблицы, которая бы лучше сделала что-то вроде этого?

спросил(а) 2011-12-25T08:56:00+04:00 8 лет, 10 месяцев назад
1
Решение
71

Не беспокойтесь о скорости выбора. Просто убедитесь, что у вас есть указатель на еду из таблицы продуктов, и он должен иметь возможность хранить миллионы строк, прежде чем получить один ряд, это будет горло бутылки.


Не попадайте в ловушку оптимизации в ближайшее время или предположите, что все будет медленным. Сначала попробуйте.

Мне нравятся "настоящие" ключи, поэтому я бы поместил пищу в качестве первичного ключа и пропустил идентификатор, но, как вы говорите, объединение в ints происходит быстрее.

ответил(а) 2011-12-25T14:41:00+04:00 8 лет, 10 месяцев назад
58

Я не вижу определений для my_mysql_function, my_mysql_function_return_query_id, $person_id и $response. Это далеко не идеально (довольно грязное решение) и может иметь ошибки, поскольку я не тестировал его, но он должен работать более эффективно. Надеюсь, это может привести вас в правильном направлении.

$existing = my_mysql_function('SELECT id FROM foods WHERE food IN (' . implode($response, ', ') . ')');
foreach($existing as $food) {
my_mysql_function("INSERT INTO people_foods VALUES ($person_id, $food['id'])");
unset($response[$food]); // Shouldn't this be $response[SOME_INTEGER]?
}

my_mysql_function('INSERT INTO foods VALUES (NULL, ' . implode($response, ', NULL), (NULL, ') . ', NULL)');
my_mysql_function("INSERT INTO people_foods VALUES ($person_id, (SELECT id FROM foods WHERE food='" . implode($response, "')), ($person_id, (SELECT id FROM foods WHERE food='") . "'))");

ответил(а) 2011-12-25T10:40:00+04:00 8 лет, 10 месяцев назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема