本文目录导读:

在Laravel中为数据库添加索引,有几种方法,我来详细说明:
使用数据库迁移(推荐)
在迁移文件中创建索引
<?php
// database/migrations/2024_01_01_000000_add_indexes_to_users_table.php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up()
{
Schema::table('users', function (Blueprint $table) {
// 普通索引
$table->index('email');
// 复合索引(多个字段)
$table->index(['country', 'city']);
// 唯一索引
$table->unique('phone');
// 指定索引名称
$table->index('status', 'idx_user_status');
});
}
public function down()
{
Schema::table('users', function (Blueprint $table) {
// 删除索引
$table->dropIndex(['email']);
$table->dropIndex(['country', 'city']);
$table->dropUnique(['phone']);
$table->dropIndex('idx_user_status');
});
}
};
在创建表时添加索引
Schema::create('products', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('sku')->unique();
$table->decimal('price', 10, 2);
$table->unsignedBigInteger('category_id');
// 在创建表时添加索引
$table->index('name');
$table->index(['category_id', 'price']);
$table->foreign('category_id')->references('id')->on('categories');
});
使用索引类型
Laravel支持多种索引类型:
Schema::table('posts', function (Blueprint $table) {
// 全文索引(MySQL/PostgreSQL)
$table->fullText('content');
// 空间索引(MySQL)
$table->spatialIndex('coordinates');
// 复合唯一索引
$table->unique(['user_id', 'post_id']);
// 索引长度限制(SQLite)
$table->index(DB::raw('LEFT(title, 100)'));
});
通过Artisan命令生成迁移
# 生成新的迁移文件 php artisan make:migration add_indexes_to_products_table --table=products # 运行迁移 php artisan migrate # 回滚最后一个迁移 php artisan migrate:rollback --step=1
常见索引建议场景
常用查询字段
// 用户表经常按邮箱、手机号查询
Schema::table('users', function (Blueprint $table) {
$table->index('email');
$table->index('phone');
});
外键字段
Schema::table('orders', function (Blueprint $table) {
$table->foreignId('user_id')->index();
$table->foreignId('product_id')->index();
});
组合查询条件
Schema::table('products', function (Blueprint $table) {
// 当经常按 category_id 和 status 查询时
$table->index(['category_id', 'status']);
});
检查现有索引
// 在代码中检查表是否已有索引
if (!Schema::hasIndex('users', 'email')) {
Schema::table('users', function (Blueprint $table) {
$table->index('email')->name('idx_user_email');
});
}
性能优化建议
// 为查询频率高的字段添加索引
$table->index('order_number'); // 订单号查询频繁
// 为排序字段添加索引
$table->index('created_at'); // 经常按时间排序
// 避免过度索引,只对WHERE、JOIN、ORDER BY中的字段添加
完整的迁移示例
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up()
{
Schema::table('products', function (Blueprint $table) {
// 添加多个索引
$table->index('category_id');
$table->index('brand_id');
$table->unique('barcode');
$table->index(['store_id', 'status']);
$table->index('updated_at');
});
}
public function down()
{
Schema::table('products', function (Blueprint $table) {
$table->dropIndex(['category_id']);
$table->dropIndex(['brand_id']);
$table->dropUnique(['barcode']);
$table->dropIndex(['store_id', 'status']);
$table->dropIndex(['updated_at']);
});
}
};
注意事项
- 不要过度添加索引:每个索引都会增加写入和存储成本
- 命名规范:通常使用
idx_前缀(普通索引)和uq_前缀(唯一索引) - 小表不需要索引:当表行数很少时,全表扫描可能比索引查找更快
- 测试影响:在添加索引前,使用
EXPLAIN命令分析查询
-- 在数据库客户端中测试查询性能 EXPLAIN SELECT * FROM products WHERE category_id = 1 AND status = 'active';
使用迁移管理索引是Laravel的最佳实践,它让索引管理版本化、可重复,并支持在团队中协作。