【问题标题】:Will Eloquent automatically add this foreign key to the primary key's index?Eloquent 会自动将此外键添加到主键的索引中吗?
【发布时间】:2016-08-12 03:38:21
【问题描述】:

假设我在 Laravel 中有一个父表和一个子表,对于表 Order,我的模型如下所示:

public function up()
{
    Schema::create('orders', function(Blueprint $table)
    {
        $table->integer('customer_id')->unsigned();
        $table->foreign('customer_id')->references('id')->on('customers')->onDelete('cascade');

        $table->increments('id');

我知道 Eloquent 会将 id 视为 orders 的主键,因此会自动在该主键上创建索引。

我应该怎么做才能确保customer_id 是主键索引的一部分,按顺序设置:

1.  customer_id
2.  id

表格示例

      Customer
    +-------------+
    | id          | --> primary key
    |- - - - - - -|
    | name        |
    | address     |
    +-------------+
           |
           |
           |
           A
      Order     
    +------------------+        
    | customer_id (fk) | --- primary key
    | id               | --- primary key        
    |- - - - - - - - - |
    | date             |
    +------------------+ 

【问题讨论】:

  • 尝试添加$table->primary(array('id', 'customer_id'));
  • 参考以下链接。我希望它会帮助你。 stackoverflow.com/questions/22477726/…
  • 有什么理由需要它作为主键索引的一部分?这对我来说没有多大意义。如果您只是在寻找有效的连接,那么外键应该就足够了,您可以通过 explain select... 来验证它
  • 我的想法是,当我使用customer_id 查询订单表时,MySQL 通过主键索引(customer_id,id)访问orders 会更快,因为customer_id 将是主键索引的第一列。我在 DB2 上工作过,它就是这样做的,但我猜 MySQL 做的不一样?

标签: laravel laravel-5 eloquent


【解决方案1】:

Eloquent 会自动将此外键添加到主键的索引中吗?

嗯,不是自动的,但很容易。

要指定自定义主键,您可以调用 Blueprint 类中的 primary() 方法,通过 $table 调用。即$table->primary()。

对于单个主键,它接受一个字符串,指定要设为主键的列的名称。

对于复合键,您可以传递要设为主要列的字符串数组。你的情况

$table->primary( ['id', 'customer_id'] )

【讨论】:

  • 我试过$table->primary(['id', 'customer_id']);,它可以工作,但我想要的是$table->primary(['customer_id', 'id']);,因为当我用customer_id查询时,索引找到订单会更快,但Eloquent没有不要让我。我收到以下消息:SQLSTATE[42000]: Syntax error or access violation: 1068 Multiple primary key defined
  • 感谢@SirjanSharma 的帮助,我不知道 $table->primary()
  • 不客气,很高兴我能帮上忙。 (如果答案可以帮助您投票,如果答案是您要寻找的答案,请将其标记为正确答案正确答案)
【解决方案2】:

我决定尝试一下,看看会发生什么。

从客户表开始,我运行了这个语句...

CREATE TABLE customers (
    id INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
    `name` VARCHAR(255),
    created_at DATETIME,
    updated_at DATETIME,
    PRIMARY KEY (id)
);

然后我创建了以下...

CREATE TABLE orders (
    id INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
    customer_id INT(11) UNSIGNED,
    created_at DATETIME,
    updated_at DATETIME,
    PRIMARY KEY (id, customer_id)
);

注意这里如果使用PRIMARY KEY (customer_id, id),会导致SQL错误。这让我相信您尝试复制的 DB2 功能在 MySQL 上不会完全一样,我们实际上需要一个外键。

然后用测试数据填充这些表后,我运行了以下...

EXPLAIN SELECT *
FROM customers
INNER JOIN orders ON customers.id = orders.customer_id;

这会导致

+------+-------------+-----------+------+---------------+------+---------+------+--------+-------------------------------------------------+
| id   | select_type | TABLE     | TYPE | possible_keys | KEY  | key_len | ref  | ROWS   | Extra                                           |
+------+-------------+-----------+------+---------------+------+---------+------+--------+-------------------------------------------------+
|    1 | SIMPLE      | customers | ALL  | PRIMARY       | NULL | NULL    | NULL |      4 |                                                 |
|    1 | SIMPLE      | orders    | ALL  | NULL          | NULL | NULL    | NULL | 262402 | USING WHERE; USING JOIN buffer (flat, BNL JOIN) |
+------+-------------+-----------+------+---------------+------+---------+------+--------+-------------------------------------------------+

然后我添加了外键...

ALTER TABLE orders ADD FOREIGN KEY customer_id (customer_id) REFERENCES customers (id) ON DELETE CASCADE ON UPDATE CASCADE;

之前使用相同的确切数据运行相同的确切解释查询,我现在得到结果...

+------+-------------+-----------+------+---------------+-------------+---------+-----------------------+-------+-------+
| id   | select_type | TABLE     | TYPE | possible_keys | KEY         | key_len | ref                   | ROWS  | Extra |
+------+-------------+-----------+------+---------------+-------------+---------+-----------------------+-------+-------+
|    1 | SIMPLE      | customers | ALL  | PRIMARY       | NULL        | NULL    | NULL                  |     4 |       |
|    1 | SIMPLE      | orders    | ref  | customer_id   | customer_id | 4       | cookbook.customers.id | 43751 |       |
+------+-------------+-----------+------+---------------+-------------+---------+-----------------------+-------+-------+

如您所见,当我添加正是我们正在寻找的外键时,评估的行数要少得多。让我感到惊讶可能是因为我不是 DBA,运行以下命令会产生相同的结果...

EXPLAIN SELECT * FROM orders WHERE customer_id = 4;

即使在这种情况下,复合主键也不会为您做任何事情,但外键却有很大帮助。

话虽如此,我认为放弃复合主键并将id 设置为主键并将customer_id 设置为外键是安全的。这还使您能够级联删除和更新。

【讨论】:

  • 哇,多么棒的解释。一定会按照你的建议去做:set the id up as primary and set the customer_id up as a foreign key 非常感谢@user3158900
猜你喜欢
  • 2010-10-24
  • 2012-12-19
  • 2011-08-24
  • 2011-08-22
  • 1970-01-01
  • 1970-01-01
  • 2012-12-30
  • 2020-06-09
相关资源
最近更新 更多