【问题标题】:How can I set up meta tables so inserting large sets of data is efficient?如何设置元表以便插入大量数据有效?
【发布时间】:2012-01-27 13:03:26
【问题描述】:

我正在进行一个调查项目,正在寻找在关系数据库中跟踪响应数据的最佳方法。假设调查记录了人们最喜欢的食物。稍后我将为新食物(卡路里)添加额外的数据。我相信我认为表格应该是这样的:

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 的操作速度更快,并且让我不会有重复的数据。我认为不利的一面是,在插入新数据之前,我必须首先在 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)" );

}

我想另一个人会使用食物名称作为食物表的主键并去掉整数,但这似乎是一种不好的做法,不适合重复数据删除,而且还会减慢查询什么我明白了。

问题

对于这样的架构,记录新响应并获取现有食物的 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
}

或者,是否有另一个表架构更适合做这样的事情?

【问题讨论】:

  • 谁能想到他们最喜欢的一百种食物?假设每个人都可以做到这一点。我可以保证大多数人的清单上都会有比萨饼、汉堡包、炸薯条等,所以很多选择可能已经在数据库中。你是如何获得卡路里的?您是否担心响应时间?
  • 是的 - 你是对的。但是,无论人们能提出多少最喜欢的食物,我关心的问题的一个方面是如何最好地优化现有数据集上的数据插入以适应这种模式(你可能有大量、无限数量的“选择” )。关于那部分的想法?卡路里用于说明链接数据的用途(因此我们不只是将所有内容存储在平面表中)。最后,响应时间可能还可以,但我真的想知道是否有比做这么多查询和在所有插入之间使用 PHP 操作数据更好的方法。
  • 考虑到一些合理的索引,数据库端对于您正在绘制的负载应该可以正常运行。但是,如果没有找到食物,您必须小心锁定食物桌,以免查看食物并将其插入。否则两个会话可能会寻找相同的食物,但没有找到它并尝试插入它。

标签: php mysql database performance database-design


【解决方案1】:

不用担心这些选择的速度。只需确保您有一个关于 foods 表中食物的索引,并且它应该能够存储数百万行,然后再获取一行将成为瓶颈。

不要陷入优化很快或假设事情会很慢的陷阱。先试试吧。

我喜欢“真正的”键,所以我会将食物作为主键并跳过 id,但正如你所说,加入整数更快。

【讨论】:

  • 好点 - 我希望它能正常工作。对 SELECT * FROM foods WHERE food IN ('.implode(',',$list_of_foods).')' 的想法如何?如果有 10k 行,我认为即使 food 是索引列也可能需要相当长的时间。我似乎记得曾经尝试过以这种方式通过电子邮件地址查找用户,它似乎很慢。
  • 我认为您将节省一些连接开销。您可能会在 php 脚本中丢失它,因为您必须处理结果。除非您需要所有列,否则不要使用 *。
【解决方案2】:

我没有看到 my_mysql_functionmy_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='") . "'))");

【讨论】:

  • 谢谢。我想我主要担心的一个问题是我仍然需要使用WHERE food IN 子句查找 100 种食物。似乎这可能会很慢。想法?
  • 我能想到的优化该部分的唯一方法是在一个字符串中执行一批查询。这样,它将利用索引的 id 列。老实说,我不确定如何对这样的东西进行基准测试,所以我不知道这是否会更快,但它肯定是有意义的。我认为使用IN 会导致全表扫描。不过,这不是 100%。
猜你喜欢
  • 1970-01-01
  • 2021-10-23
  • 1970-01-01
  • 2013-01-30
  • 1970-01-01
  • 2011-02-01
  • 2013-03-25
  • 1970-01-01
  • 2020-03-05
相关资源
最近更新 更多