使用实体框架时规范化SQL表

本文关键字:规范化 SQL 框架 实体 | 更新日期: 2023-09-27 17:58:01

让我首先说我不是SQL专家,新手适合

我有一个日志表,目前有1000万行:

Logs( Id, FKId, Source, Message )

我想知道规范化我的源和消息表是否有益。在1000万行中,只有200000个DISTINCT Source和100万个DISTINCT Messages。为了规范化这些数据,我想我还需要两个表。具有Id和Text的Source,以及具有Id和Text的Message(或者它们可能是同一个表?)

我目前正在使用实体框架插入行。我想知道Entity Framework将如何处理这一问题,以及我是否能获得我想要的性能提升,特别是在尝试执行"Message LIKE'%error%'"时,或者只是通过将整个事情缩小从而减少分页。

我认为EF不可能自动为我弄清楚新插入的消息是否唯一,所以我必须先弄清楚,或者通过存储过程进行插入。如果我每天在这个表中插入200万次,那么通过EF调用SP与相比性能如何变化

context.Logs.Add(log)
context.Save();

使用实体框架时规范化SQL表

我假设您的C#代码会有这样的方法签名:

public void AddLogMessage(Int32 foreignKeyId, String source, String message)

如果你修改你的数据库设计成这样:

Logs( LogId, FKId, SourceId, MessageId )
Sources( SourceId, Value )
Messages( MessageId, Value )
-- with all appropriate FK constraints on Logs->Sources and Logs->Messages

然后,您会发现自己编写的C#/Linq比查找源和消息文本并将它们放入记录所需的还要多(除了使用更多的DB聊天之外)。实际上,这最好使用存储过程来完成,您可以将其作为函数导入添加到DBContext中:

CREATE PROCEDURE AddLogMessage
    @fkId int,
    @source nvarchar(255),
    @message nvarchar(1024)
AS
BEGIN
    SET NOCOUNT ON
    BEGIN TRANSACTION
    DECLARE @sourceId int = SELECT SourceId FROM Sources WHERE Value = @source
    IF @sourceId IS NULL
    BEGIN
        INSERT INTO Sources ( Value ) VALUES ( @source )
        SET @sourceId = SELECT SCOPE_IDENTITY()
    END
    DECLARE @messageId int = SELECT MessageId FROM Messages WHERE Value = @message
    IF @messageId IS NULL
    BEGIN
        INSERT INTO Messages ( Value ) VALUES ( @message)
        SET @messageId = SELECT SCOPE_IDENTITY()
    END
    INSERT INTO Logs ( @fkId, @sourceId, @messageId )
    COMMIT TRANSACTION
END

将它导入DBContext后,只需像调用任何其他函数一样调用它:

public void AddLogMessage(Int32 foreignKeyId, String source, String message) {
    this.dbContext.AddLogMessage( foreignkeyId, source, message );
}