zoukankan      html  css  js  c++  java
  • SQL Server 维护冗余

    介绍

    冗余是维护的魔鬼, 是性能优化的天使

    常见的冗余有

    1. computed column

    2. foreign table 的识别字段

    维护冗余的方案有很多. 比如 computed column, trigger, view, 甚至在应用层写 event bus.

    但不同情况利弊也不同. 还得看场景决定. 

    我目前使用 computed column 和 trigger 来维护冗余.

    对比在应用层维护, 好处是可以直接修改 SQL, 冗余一样可以正常 working (在业务还不稳定的情况下, 直接使用数据库来做信息管理可以提高效率和节约试错成本)

    另一个好处是不需要在应用层额外的开发一套维护方案, 要知道 EF core 并没有现成的方案,甚至连 trigger 机制都没有 build-in 的.

    Computed Column Same Row

    比如 Subtoal, TotalAmount 这类的字段. 

    比较简单的 computed column 是依赖同一个 row 里面的字段, 比如 FullName, Subtotal 

    ALTER TABLE InvoiceItem DROP COLUMN Subtotal;
    GO
    ALTER TABLE InvoiceItem ADD Subtotal as (CAST(Qty as DECIMAL(19)) * UnitPrice) PERSISTED NOT NULL;
    GO

    用普通的 computed column 就可以解决了, 只能依赖同行, 而且依赖的字段不可以是 computed column

    如果超出这个限制, 那么就需要用其它方案了.

    Computed Column Cross Table

    如果是跨表比如 TotalAmount 要 SUM 的这种.

    就要使用 Trigger 监听所有依赖字段, 然后重新跑 Computed 方法

    例子: 

    DROP TRIGGER TR_InvoiceItem_AfterInsert_ForRedundancy_Invoice_TotalAmount;
    GO
    CREATE TRIGGER TR_InvoiceItem_AfterInsert_ForRedundancy_Invoice_TotalAmount ON InvoiceItem
    AFTER INSERT 
    AS
        IF (ROWCOUNT_BIG() = 0) RETURN;
        SET NOCOUNT ON;
        UPDATE Invoice SET TotalAmount = (SELECT SUM(Subtotal) FROM InvoiceItem WHERE InvoiceId = Invoice.InvoiceId)
        FROM Invoice 
        INNER JOIN inserted ON Invoice.InvoiceId = inserted.InvoiceId;
    GO
    
    DROP TRIGGER TR_InvoiceItem_AfterDelete_ForRedundancy_Invoice_TotalAmount;
    GO
    CREATE TRIGGER TR_InvoiceItem_AfterDelete_ForRedundancy_Invoice_TotalAmount ON InvoiceItem
    AFTER DELETE 
    AS
        IF (ROWCOUNT_BIG() = 0) RETURN;
        SET NOCOUNT ON;
        UPDATE Invoice SET TotalAmount = (SELECT SUM(Subtotal) FROM InvoiceItem WHERE InvoiceId = Invoice.InvoiceId)
        FROM Invoice 
        INNER JOIN deleted ON Invoice.InvoiceId = deleted.InvoiceId;
    GO
    
    DROP TRIGGER TR_InvoiceItem_AfterUpdate_ForRedundancy_Invoice_TotalAmount;
    GO
    CREATE TRIGGER TR_InvoiceItem_AfterUpdate_ForRedundancy_Invoice_TotalAmount ON InvoiceItem
    AFTER UPDATE 
    AS
        IF (ROWCOUNT_BIG() = 0) RETURN;
        SET NOCOUNT ON;
        UPDATE Invoice SET TotalAmount = (SELECT SUM(Subtotal) FROM InvoiceItem WHERE InvoiceId = Invoice.InvoiceId)
        FROM Invoice
        LEFT JOIN deleted ON Invoice.InvoiceId = deleted.InvoiceId
        LEFT JOIN inserted ON Invoice.InvoiceId = inserted.InvoiceId
        WHERE (deleted.InvoiceItemId IS NOT NULL OR inserted.InvoiceItemId IS NOT NULL) AND (inserted.Subtotal != deleted.Subtotal OR inserted.InvoiceId != deleted.InvoiceId);
    GO

    Foreign Table 识别字段

    比如 Name, Code, Number 之类的. 由于 foreign table 是依靠 Id 作为 key, 而 Id 对业务来说不具备识别能力, 所以一般上会需要一些识别字段

    每次 join table 或者识别字段对性能很伤, 所以就有了 Foreign Table 识别字段的冗余.

    同样可以使用 Trigger 来维护

    例子:

    DROP TRIGGER TR_InvoiceItem_AfterInsert_ForRedundancy_InvoiceItem_InvoiceNumber;
    GO
    CREATE TRIGGER TR_InvoiceItem_AfterInsert_ForRedundancy_InvoiceItem_InvoiceNumber ON InvoiceItem
    AFTER INSERT 
    AS
        IF (ROWCOUNT_BIG() = 0) RETURN;
        SET NOCOUNT ON;
        UPDATE InvoiceItem SET InvoiceNumber = Invoice.Number
        FROM InvoiceItem
        INNER JOIN inserted ON InvoiceItem.InvoiceItemId = inserted.InvoiceItemId
        LEFT JOIN Invoice ON InvoiceItem.InvoiceId = Invoice.InvoiceId
    GO
     
    DROP TRIGGER TR_InvoiceItem_AfterUpdate_ForRedundancy_InvoiceItem_InvoiceNumber;
    GO
    CREATE TRIGGER TR_InvoiceItem_AfterUpdate_ForRedundancy_InvoiceItem_InvoiceNumber ON InvoiceItem
    AFTER Update 
    AS
        IF (ROWCOUNT_BIG() = 0) RETURN;
        SET NOCOUNT ON;
        UPDATE InvoiceItem SET InvoiceNumber = Invoice.Number
        FROM InvoiceItem
        INNER JOIN inserted ON InvoiceItem.InvoiceItemId = inserted.InvoiceItemId
        LEFT JOIN deleted ON InvoiceItem.InvoiceItemId = deleted.InvoiceItemId
        LEFT JOIN Invoice ON InvoiceItem.InvoiceId = Invoice.InvoiceId
        WHERE inserted.InvoiceId != deleted.InvoiceId;
    GO
    
    UPDATE InvoiceItem SET Qty = Qty + 1 WHERE InvoiceItemId = 1;
    
    DROP TRIGGER TR_Invoice_AfterUpdate_ForRedundancy_InvoiceItem_InvoiceNumber;
    GO
    CREATE TRIGGER TR_Invoice_AfterUpdate_ForRedundancy_InvoiceItem_InvoiceNumber ON Invoice
    AFTER UPDATE 
    AS
        IF (ROWCOUNT_BIG() = 0) RETURN;
        SET NOCOUNT ON;
        UPDATE InvoiceItem SET InvoiceNumber = inserted.Number
        FROM InvoiceItem
        INNER JOIN inserted ON InvoiceItem.InvoiceId = inserted.InvoiceId
        LEFT JOIN deleted ON InvoiceItem.InvoiceId = deleted.InvoiceId
        WHERE inserted.Number != deleted.Number;
    GO
  • 相关阅读:
    【剑指Offer面试编程题】题目1504:把数组排成最小的数--九度OJ
    【剑指Offer面试编程题】题目1373:整数中1出现的次数--九度OJ
    【剑指Offer面试编程题】题目1372:最大子向量和--九度OJ
    【剑指Offer面试编程题】题目1371:最小的K个数--九度OJ
    vue路由传参
    Es5.Es6区别
    面向对象和面向过程
    vuex
    Vue脚手架使用
    vue中fetch请求
  • 原文地址:https://www.cnblogs.com/keatkeat/p/15072426.html
Copyright © 2011-2022 走看看