在我的数据库中,我有3个主要的类别,即育种者,马匹和种族。这3个表具有多对多关系。一个饲养员可以有多匹马,一匹马可以有多个饲养员。一匹马也可以参加多个比赛,而一个比赛中可以有多个马参加。现在,我想查询一个种鸽的比赛统计数据。使用实体框架,我有以下代码行:
var races = DbContext.HorseBreeders
.Where(w => w.BreederId == someint)
.SelectMany(s => s.Horse.Races)
.ToList();
并且此代码生成以下mysql查询:
SELECT `w.Horse.Races`.`Id`, `w.Horse.Races`.`FinishTime`, `w.Horse.Races`.`Horse_Id`, `w.Horse.Races`.`Race_Id`
FROM `HorseBreeders` AS `w`
INNER JOIN `Horses` AS `w.Horse` ON `w`.`HorseId` = `w.Horse`.`Id`
INNER JOIN `RaceEntries` AS `w.Horse.Races` ON `w.Horse`.`Id` = `w.Horse.Races`.`Horse_Id`
WHERE `w`.`BreederId` = someint
此查询大约需要30秒。
在Mssql中,具有类似查询的相同结构花了不到一秒钟的时间。但是在Mysql中,它花费了太多时间。我在做什么错了?
DbContext类:
public class Breeder
{
public int Id { get; set; }
[StringLength(50)]
public string Name { get; set; }
public virtual ICollection<HorseBreeder> Horses { get; set; }
}
public class Horse
{
public int Id { get; set; }
[StringLength(50)]
public string Name { get; set; }
public int? Father_Id { get; set; }
public virtual Horse Father { get; set; }
public int? Mother_Id { get; set; }
public virtual Horse Mother { get; set; }
public string BirthPlace { get; set; }
public DateTime? BirthDate { get; set; }
public virtual ICollection<HorseBreeder> Breeders { get; set; }
public virtual ICollection<RaceEntry> Races { get; set; }
public virtual ICollection<Horse> FatherChilds { get; set; }
public virtual ICollection<Horse> MotherChilds { get; set; }
}
public class HorseBreeder
{
public int HorseId { get; set; }
public Horse Horse { get; set; }
public int BreederId { get; set; }
public Breeder Breeder { get; set; }
}
public class Race
{
public int Id { get; set; }
public DateTime Time { get; set; }
public string Name { get; set; }
public virtual ICollection<RaceEntry> Horses { get; set; }
}
public class RaceEntry
{
public int Id { get; set; }
public int Race_Id { get; set; }
public virtual Race Race { get; set; }
public int Horse_Id { get; set; }
public virtual Horse Horse { get; set; }
public short? FinishTime { get; set; }
}
DbContext OnModelCreating:
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
// Horse
builder.Entity<HorseBreeder>()
.HasKey(bc => new { bc.HorseId, bc.BreederId });
builder.Entity<HorseBreeder>()
.HasOne(bc => bc.Horse)
.WithMany(b => b.Breeders)
.HasForeignKey(bc => bc.HorseId);
builder.Entity<HorseBreeder>()
.HasOne(bc => bc.Breeder)
.WithMany(c => c.Horses)
.HasForeignKey(bc => bc.BreederId);
builder.Entity<Horse>()
.HasOne(p => p.Father)
.WithMany(p => p.FatherChilds)
.HasForeignKey(p => p.Father_Id);
builder.Entity<Horse>()
.HasOne(p => p.Mother)
.WithMany(p => p.MotherChilds)
.HasForeignKey(p => p.Mother_Id);
// RaceEntry
builder.Entity<RaceEntry>()
.HasOne(m => m.Race)
.WithMany(t => t.Horses)
.HasForeignKey(m => m.Race_Id);
builder.Entity<RaceEntry>()
.HasOne(m => m.Horse)
.WithMany(t => t.Races)
.HasForeignKey(m => m.Horse_Id);
}
数据库创建迁移:
public partial class initial_create : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Breeders",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
Name = table.Column<string>(maxLength: 50, nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Breeders", x => x.Id);
});
migrationBuilder.CreateTable(
name: "Horses",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
Name = table.Column<string>(maxLength: 50, nullable: true),
Father_Id = table.Column<int>(nullable: true),
Mother_Id = table.Column<int>(nullable: true),
BirthPlace = table.Column<string>(nullable: true),
BirthDate = table.Column<DateTime>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Horses", x => x.Id);
table.ForeignKey(
name: "FK_Horses_Horses_Father_Id",
column: x => x.Father_Id,
principalTable: "Horses",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
table.ForeignKey(
name: "FK_Horses_Horses_Mother_Id",
column: x => x.Mother_Id,
principalTable: "Horses",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
});
migrationBuilder.CreateTable(
name: "Races",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
Time = table.Column<DateTime>(nullable: false),
Name = table.Column<string>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Races", x => x.Id);
});
migrationBuilder.CreateTable(
name: "HorseBreeders",
columns: table => new
{
HorseId = table.Column<int>(nullable: false),
BreederId = table.Column<int>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_HorseBreeders", x => new { x.HorseId, x.BreederId });
table.ForeignKey(
name: "FK_HorseBreeders_Breeders_BreederId",
column: x => x.BreederId,
principalTable: "Breeders",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_HorseBreeders_Horses_HorseId",
column: x => x.HorseId,
principalTable: "Horses",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "RaceEntries",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
Race_Id = table.Column<int>(nullable: false),
Horse_Id = table.Column<int>(nullable: false),
FinishTime = table.Column<short>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_RaceEntries", x => x.Id);
table.ForeignKey(
name: "FK_RaceEntries_Horses_Horse_Id",
column: x => x.Horse_Id,
principalTable: "Horses",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_RaceEntries_Races_Race_Id",
column: x => x.Race_Id,
principalTable: "Races",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_HorseBreeders_BreederId",
table: "HorseBreeders",
column: "BreederId");
migrationBuilder.CreateIndex(
name: "IX_Horses_Father_Id",
table: "Horses",
column: "Father_Id");
migrationBuilder.CreateIndex(
name: "IX_Horses_Mother_Id",
table: "Horses",
column: "Mother_Id");
migrationBuilder.CreateIndex(
name: "IX_RaceEntries_Horse_Id",
table: "RaceEntries",
column: "Horse_Id");
migrationBuilder.CreateIndex(
name: "IX_RaceEntries_Race_Id",
table: "RaceEntries",
column: "Race_Id");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "HorseBreeders");
migrationBuilder.DropTable(
name: "RaceEntries");
migrationBuilder.DropTable(
name: "Breeders");
migrationBuilder.DropTable(
name: "Horses");
migrationBuilder.DropTable(
name: "Races");
}
}