Php 如何设置元表以便插入大型数据集是有效的?
我正在做一个调查项目,正在寻找在关系数据库中跟踪响应数据的最佳方法。假设调查记录了人们最喜欢的食物。稍后,我将为新食品(卡路里)添加更多数据。我相信我认为这些表格应该是这样的: 人Php 如何设置元表以便插入大型数据集是有效的?,php,mysql,database,performance,database-design,Php,Mysql,Database,Performance,Database Design,我正在做一个调查项目,正在寻找在关系数据库中跟踪响应数据的最佳方法。假设调查记录了人们最喜欢的食物。稍后,我将为新食品(卡路里)添加更多数据。我相信我认为这些表格应该是这样的: 人 id | name ================== 1 | John 2 | Suzy 3 | Joe 4 | Laura 5 | Bob 食品 id | food | calories ============================ 10 | spaghetti | 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
选择
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
这使得我可以在表之间的连接中使用整数,这使得进行连接
很快,并且避免了重复数据。我认为,缺点是,在插入新数据之前,我必须首先在foods表上查找ID,以确保您添加的食物不存在
这对于一个小数据库来说已经足够简单了,但是如果我决定向人们询问他们最喜欢的100种食物,而这项调查将发送给数千人,那会怎么样呢?即使在foods表上有一个索引,这意味着每次插入100个选项时,我们都需要查询foods以获得现有食品的ID。(这是否意味着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)" );
}
$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
}
我想另一种方法是使用food名称作为foods表的主键,并去掉整数,但这似乎是一种不好的做法,不利于重复数据消除,也会减慢我所理解的查询速度
问题
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
对于这样的模式,记录新响应并获取现有食物的ID或插入食物的最有效方法是什么?如果我插入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)" );
}
$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
}
或者,有没有其他更适合这样做的表模式?我没有看到
我的myu mysql\u函数
、我的myu mysql\u函数_return\u query\u id
、$person\u 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='") . "'))");
不要担心这些选择的速度。只要确保你有一个食物表中食物的索引,它应该能够存储数百万行,否则一行就会成为瓶颈 不要陷入优化的陷阱,以为事情会很快或假设事情会很慢。先试试
我喜欢“真实”键,所以我会把食物作为主键,跳过id,但正如你所说,加入ints更快。谁能想到他们喜欢的100种食物?假设每个人都能做到这一点。我可以保证大多数人都会吃比萨饼、汉堡包、炸薯条等。他们的名单上可能已经有很多选择了。你是如何获得卡路里的?你是担心响应时间还是什么?是的,你是对的。但是,不管人们会想出多少最喜欢的食物,我关心的问题是如何最好地为这种模式优化现有数据集上的数据插入(在这种模式下,您可能有大量、无限数量的“选择”)。你对此有何想法?卡路里的存在是为了说明链接数据的用途(因此我们不只是将所有内容存储在一个平面表格中)。最后,响应时间可能还可以,但我真的想知道是否有比在所有插入之间执行如此多的查询和使用PHP处理数据更好的方法。给定一些合理的索引,对于您正在绘制的负载,数据库端应该可以执行。但是,如果没有找到食物,你必须小心地锁好食物桌,以免在里面寻找食物并将其插入。否则,两个会话可能会寻找相同的食物,但没有找到,并且都尝试插入。谢谢。我想我的一个主要担忧是,我仍然需要使用
WHERE food IN
子句查找100种食物。看起来可能会很慢。想法?我能想到的优化该部分的唯一方法是在一个字符串中执行一批查询。这样,它将使用索引id列。老实说,我不确定如何对这样的东西进行基准测试,所以我不知道这样做是否会更快,但这确实是有意义的。我认为在中使用会导致全表扫描。不过,这不是100%。很好的观点——我希望它能很好地工作。关于做SELECT*的想法是什么?(“.内爆(”,“,$list\u of\u foods)。”
?如果有10k行,我认为即使food
是一个索引列,也需要相当长的时间。我似乎记得曾经尝试过用这种方式通过电子邮件地址查找用户,但速度似乎很慢。我认为这样可以节省一些连接开销。您可能会在php脚本中丢失它,因为您必须处理结果。除非需要所有列,否则不要这样做。