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

时间:2016-08-11 17:22:54

标签: laravel laravel-5 eloquent

假设我在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会认为idorders的主键,因此会在该主键上自动创建索引。

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

1.  customer_id
2.  id

表格示例

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

2 个答案:

答案 0 :(得分:2)

  

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

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

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

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

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

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

答案 1 :(得分:0)

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

从customers表开始,我运行了这个声明......

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设置为外键是安全的。这也为您提供了级联删除和更新的好处。