惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

D
Darknet – Hacking Tools, Hacker News & Cyber Security
T
Tenable Blog
阮一峰的网络日志
阮一峰的网络日志
S
Schneier on Security
A
Arctic Wolf
Latest news
Latest news
C
Check Point Blog
S
SegmentFault 最新的问题
T
Tor Project blog
B
Blog RSS Feed
The GitHub Blog
The GitHub Blog
爱范儿
爱范儿
腾讯CDC
C
CERT Recently Published Vulnerability Notes
A
About on SuperTechFans
U
Unit 42
L
LINUX DO - 热门话题
罗磊的独立博客
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
MyScale Blog
MyScale Blog
D
Docker
Blog — PlanetScale
Blog — PlanetScale
GbyAI
GbyAI
V
Vulnerabilities – Threatpost
月光博客
月光博客
aimingoo的专栏
aimingoo的专栏
WordPress大学
WordPress大学
Security Latest
Security Latest
博客园_首页
C
Cybersecurity and Infrastructure Security Agency CISA
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
AI
AI
H
Hacker News: Front Page
C
CXSECURITY Database RSS Feed - CXSecurity.com
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Google DeepMind News
Google DeepMind News
T
Tailwind CSS Blog
TaoSecurity Blog
TaoSecurity Blog
博客园 - 司徒正美
云风的 BLOG
云风的 BLOG
S
Securelist
Engineering at Meta
Engineering at Meta
D
DataBreaches.Net
P
Privacy & Cybersecurity Law Blog
T
Threat Research - Cisco Blogs
V2EX - 技术
V2EX - 技术
Vercel News
Vercel News
N
News and Events Feed by Topic
Security Archives - TechRepublic
Security Archives - TechRepublic
S
Secure Thoughts

博客园 - 我才是银古

第16章:常见问题、排错与最佳实践 第15章:扩展生态、MCAD 与外部集成 第12章:实战案例:机械结构与 3D 打印零件 第14章:构建、测试、调试与贡献流程 第13章:OpenSCAD 源码架构与核心执行流程 第11章:预览、渲染、网格精度与性能优化 第09章:列表推导、递归与算法建模 第08章:参数化零件库与复用设计 第10章:导入导出、命令行与自动化 第06章:CSG 布尔建模方法 第07章:二维图形、拉伸、旋转与投影 第05章:基础几何、坐标系与变换 第04章:参数、变量、函数、模块与作用域 OpenSCAD 教程目录 第03章:OpenSCAD 语言基础 第02章:安装、环境配置与开发工作流 第01章:OpenSCAD 项目全景与学习路线 第02章:源码获取、编译与开发环境配置 第01章:OCCT项目全景与学习路线 第18章:二次开发实战与综合案例 第18章:综合实战案例 第17章:数据交换与协同 第16章:源码架构与二次开发 第15章:插件与自定义工作台开发 第14章:Python脚本宏与自动化 第13章:FEM仿真分析 第12章:CAM数控加工 第11章:SurfaceMesh与逆向工程 第10章:Draft二维绘图与BIM建筑 第09章:工程图TechDraw 第07章:参数化表达式与Spreadsheet 第08章:装配设计Assembly 第06章:Part工作台与几何内核 第05章:PartDesign实体特征建模 第04章:草图Sketcher约束建模 第02章:安装版本与工作环境配置 第03章:界面工作台与基础操作 第01章:项目全景与学习路线 第十二章:插件开发、研究功能与最佳实践 第十章:定时任务与自动化(Cron) 第七章:技能、记忆与自学习闭环 第八章:MCP 集成与上下文文件 第六章:工具系统与终端后端 第五章:模型供应商与配置体系 Hermes Agent 教程目录 第十一章:语音、视觉、浏览器与子代理协作 第四章:CLI/TUI 与会话管理 第十二章:学习路线、实战方案与最佳实践 第十一章:源码结构、开发调试与插件开发 第十章:自动化、远程访问、日志与排障 第九章:Control UI、节点、Canvas 与语音能力 第七章:工具、技能、插件与能力扩展 第八章:安全模型、访问控制与沙箱实践 第六章:Agent 工作区、会话与多智能体路由 第五章:多通道消息接入与聊天平台配置 第四章:配置体系、模型接入与认证管理 第三章:Gateway 架构、协议与运行机制 第二章:安装、环境准备与快速上手 第一章:OpenClaw 项目概览与核心定位 oh-my-openagent 教程目录 09-命令模型回退与配置参考 10-实战案例最佳实践与故障排除 05-工作模式-Ultrawork-Prometheus-Atlas 08-Hooks与MCP系统 06-Category与Skill系统 07-核心工具链 04-智能体全景详解 03-安装与环境配置 02-整体架构与多模型编排机制 01-项目简介与核心理念 01-项目概览与学习路线 02-安装部署与工具适配 03-Skill机制与using-superpowers 05-TDD系统化调试与完成前验证 04-需求澄清方案设计与计划编写 07-并行智能体子智能体与Git-Worktree 第六章:代码审查、反馈处理与分支收尾 08-中国特色Skills与本土团队落地 09-MCP构建工作流执行与自定义Skill 第23章:FreeCAD-Python-API Clipper2 C# 源码解读教程 第19章:PolyTree 多边形树结构 第20章:实际应用与最佳实践 第18章:Minkowski 和与差 第17章:RectClip 矩形裁剪优化 第16章:ClipperOffset 偏移类详解 第15章:填充规则详解 第14章:布尔运算执行流程 第13章:ClipperD 浮点裁剪类 第11章:OutRec 与 OutPt 输出结构 第9章:Active 活动边结构 第10章:Vertex 顶点与 LocalMinima 局部极小值 第12章:Clipper64 裁剪类详解 第7章:高精度运算与128位整数 第8章:ClipperBase 基类详解 第5章:枚举类型与常量定义 第6章:InternalClipper 内部工具类 第2章:核心数据结构 - Point64、PointD 第3章:路径与多边形表示 - Path64、PathD、Paths64、PathsD 第4章:矩形边界 - Rect64、RectD
第十章:分表分库与多租户
我才是银古 · 2026-06-21 · via 博客园 - 我才是银古

第十章:分表分库与多租户

目录


10.1 分表分库概述

10.1.1 为什么需要分表分库

当数据量达到一定规模时,单表单库会遇到性能瓶颈:

// 问题场景示例
// 订单表数据量:5000万条
// 查询性能:即使有索引,查询也需要几秒钟
var orders = db.Queryable<Order>()
    .Where(o => o.CreateTime >= DateTime.Now.AddDays(-30))
    .ToList(); // 慢查询

// 插入性能:高并发插入时锁竞争严重
for (int i = 0; i < 10000; i++)
{
    db.Insertable(new Order()).ExecuteCommand(); // 性能下降
}

分表分库的优势

  • 提高查询性能:单表数据量减少
  • 提升并发能力:减少锁竞争
  • 便于维护:按业务逻辑分离数据
  • 支持数据归档:历史数据独立存储

10.1.2 分表分库策略

水平分表:按照一定规则将同一个表的数据分散到多个表中

order_2023_01, order_2023_02, order_2023_03...
order_user_1, order_user_2, order_user_3...

垂直分表:将表中某些字段拆分到另一个表

user (基础信息) + user_profile (扩展信息)
product (商品信息) + product_detail (详细描述)

垂直分库:按业务模块拆分到不同数据库

user_db (用户中心)
order_db (订单中心)
product_db (商品中心)

10.2 水平分表

10.2.1 SplitTable配置

SqlSugar使用SplitTable特性实现分表:

[SplitTable(SplitType.Month)]  // 按月分表
[SugarTable("order_{year}{month}{day}")]
public class Order
{
    [SugarColumn(IsPrimaryKey = true)]
    public long Id { get; set; }
    
    public string OrderNo { get; set; }
    
    [SplitField]  // 分表字段
    public DateTime CreateTime { get; set; }
    
    public decimal Amount { get; set; }
    public int UserId { get; set; }
}

// 使用分表
public class OrderService
{
    private readonly SqlSugarClient _db;
    
    public OrderService(SqlSugarClient db)
    {
        _db = db;
    }
    
    // 插入时自动路由到对应的表
    public void AddOrder(Order order)
    {
        _db.Insertable(order).SplitTable().ExecuteCommand();
    }
    
    // 查询时自动路由
    public List<Order> GetOrdersByTime(DateTime start, DateTime end)
    {
        return _db.Queryable<Order>()
            .SplitTable(tabs => tabs
                .Where(start, end)) // 指定时间范围
            .Where(o => o.CreateTime >= start && o.CreateTime <= end)
            .ToList();
    }
}

10.2.2 按时间分表

按时间分表是最常见的场景:

// 按月分表
[SplitTable(SplitType.Month)]
[SugarTable("log_{year}{month}")]
public class SystemLog
{
    [SugarColumn(IsPrimaryKey = true)]
    public long Id { get; set; }
    
    [SplitField]
    public DateTime CreateTime { get; set; }
    
    public string Message { get; set; }
    public string Level { get; set; }
}

// 按天分表
[SplitTable(SplitType.Day)]
[SugarTable("order_{year}{month}{day}")]
public class Order
{
    [SugarColumn(IsPrimaryKey = true)]
    public long Id { get; set; }
    
    [SplitField]
    public DateTime CreateTime { get; set; }
    
    public string OrderNo { get; set; }
}

// 按年分表
[SplitTable(SplitType.Year)]
[SugarTable("archive_{year}")]
public class ArchiveData
{
    [SugarColumn(IsPrimaryKey = true)]
    public long Id { get; set; }
    
    [SplitField]
    public DateTime CreateTime { get; set; }
    
    public string Content { get; set; }
}

// 实际使用
public class LogService
{
    private readonly SqlSugarClient _db;
    
    // 记录日志(自动创建表)
    public void Log(string message, string level)
    {
        var log = new SystemLog
        {
            CreateTime = DateTime.Now,
            Message = message,
            Level = level
        };
        
        _db.Insertable(log)
            .SplitTable()
            .ExecuteCommand();
    }
    
    // 查询指定月份的日志
    public List<SystemLog> GetLogsByMonth(int year, int month)
    {
        var start = new DateTime(year, month, 1);
        var end = start.AddMonths(1).AddDays(-1);
        
        return _db.Queryable<SystemLog>()
            .SplitTable(tabs => tabs.Where(start, end))
            .Where(l => l.CreateTime >= start && l.CreateTime <= end)
            .ToList();
    }
    
    // 查询最近7天的日志
    public List<SystemLog> GetRecentLogs()
    {
        var start = DateTime.Now.AddDays(-7);
        var end = DateTime.Now;
        
        return _db.Queryable<SystemLog>()
            .SplitTable(tabs => tabs.Where(start, end))
            .Where(l => l.CreateTime >= start && l.CreateTime <= end)
            .OrderBy(l => l.CreateTime, OrderByType.Desc)
            .ToList();
    }
}

10.2.3 按范围分表

按照数据范围或业务规则分表:

// 自定义分表规则
public class OrderByUserIdSplit
{
    // 根据用户ID分表(每10000个用户一张表)
    [SugarTable("order_user_{table}")]
    public class Order
    {
        [SugarColumn(IsPrimaryKey = true)]
        public long Id { get; set; }
        
        public int UserId { get; set; }
        public string OrderNo { get; set; }
        public DateTime CreateTime { get; set; }
    }
    
    // 实现分表逻辑
    public static string GetTableName(int userId)
    {
        int tableIndex = userId / 10000;
        return $"order_user_{tableIndex}";
    }
}

// 使用自定义分表
public class OrderRepository
{
    private readonly SqlSugarClient _db;
    
    // 插入订单
    public void AddOrder(Order order)
    {
        var tableName = OrderByUserIdSplit.GetTableName(order.UserId);
        
        _db.Insertable(order)
            .AS(tableName) // 指定表名
            .ExecuteCommand();
    }
    
    // 查询用户订单
    public List<Order> GetUserOrders(int userId)
    {
        var tableName = OrderByUserIdSplit.GetTableName(userId);
        
        return _db.Queryable<Order>()
            .AS(tableName)
            .Where(o => o.UserId == userId)
            .ToList();
    }
}

// 范围分表:按订单金额
public class OrderByAmountSplit
{
    // 小额订单表:0-100元
    // 中额订单表:100-1000元
    // 大额订单表:1000元以上
    
    public static string GetTableName(decimal amount)
    {
        if (amount < 100)
            return "order_small";
        else if (amount < 1000)
            return "order_medium";
        else
            return "order_large";
    }
}

10.3 自动路由

10.3.1 分表路由规则

SqlSugar支持灵活的路由规则:

// 配置全局分表策略
db.CurrentConnectionConfig.MoreSettings = new ConnMoreSettings
{
    // 自动创建分表
    IsAutoCreateTable = true,
    
    // 分表策略
    SplitTableFunc = (entityInfo) =>
    {
        // 自定义分表逻辑
        if (entityInfo.Type == typeof(Order))
        {
            // 动态返回表名列表
            var tables = new List<string>();
            for (int i = 1; i <= 12; i++)
            {
                tables.Add($"order_2024{i:00}");
            }
            return tables;
        }
        return null;
    }
};

// 高级路由配置
public class AdvancedSplitTableService
{
    private readonly SqlSugarClient _db;
    
    // 多条件路由
    public List<Order> GetOrders(OrderQueryDto query)
    {
        var queryable = _db.Queryable<Order>();
        
        // 根据查询条件确定需要查询的表
        if (query.StartTime.HasValue && query.EndTime.HasValue)
        {
            // 按时间范围路由
            queryable = queryable.SplitTable(tabs => 
                tabs.Where(query.StartTime.Value, query.EndTime.Value));
        }
        else if (query.UserId.HasValue)
        {
            // 按用户ID路由
            var tableName = GetTableNameByUserId(query.UserId.Value);
            queryable = queryable.AS(tableName);
        }
        else
        {
            // 查询所有分表
            queryable = queryable.SplitTable();
        }
        
        return queryable
            .WhereIF(query.UserId.HasValue, o => o.UserId == query.UserId)
            .WhereIF(query.StartTime.HasValue, o => o.CreateTime >= query.StartTime)
            .WhereIF(query.EndTime.HasValue, o => o.CreateTime <= query.EndTime)
            .ToList();
    }
    
    private string GetTableNameByUserId(int userId)
    {
        return $"order_user_{userId / 10000}";
    }
}

10.3.2 动态表名

在运行时动态指定表名:

// 动态表名查询
public class DynamicTableService
{
    private readonly SqlSugarClient _db;
    
    // 动态查询指定表
    public List<T> QueryTable<T>(string tableName) where T : class, new()
    {
        return _db.Queryable<T>()
            .AS(tableName)
            .ToList();
    }
    
    // 动态插入到指定表
    public int InsertToTable<T>(T entity, string tableName) where T : class, new()
    {
        return _db.Insertable(entity)
            .AS(tableName)
            .ExecuteCommand();
    }
    
    // 批量查询多个分表
    public List<Order> QueryMultipleTables(List<string> tableNames)
    {
        var allOrders = new List<Order>();
        
        foreach (var tableName in tableNames)
        {
            var orders = _db.Queryable<Order>()
                .AS(tableName)
                .ToList();
            allOrders.AddRange(orders);
        }
        
        return allOrders;
    }
    
    // 使用Union查询多个分表
    public List<Order> QueryWithUnion(DateTime start, DateTime end)
    {
        // 获取需要查询的表名
        var tableNames = GetTableNames(start, end);
        
        if (tableNames.Count == 0)
            return new List<Order>();
        
        // 构建Union查询
        var queryable = _db.Queryable<Order>().AS(tableNames[0]);
        
        for (int i = 1; i < tableNames.Count; i++)
        {
            queryable = queryable.Union(
                _db.Queryable<Order>().AS(tableNames[i])
            );
        }
        
        return queryable
            .Where(o => o.CreateTime >= start && o.CreateTime <= end)
            .ToList();
    }
    
    private List<string> GetTableNames(DateTime start, DateTime end)
    {
        var tables = new List<string>();
        var current = new DateTime(start.Year, start.Month, 1);
        var endMonth = new DateTime(end.Year, end.Month, 1);
        
        while (current <= endMonth)
        {
            tables.Add($"order_{current:yyyyMM}");
            current = current.AddMonths(1);
        }
        
        return tables;
    }
}

10.4 垂直分库

10.4.1 多库配置

配置多个数据库连接:

// 配置多个数据库
public class MultiDatabaseConfig
{
    public static SqlSugarScope CreateMultiDatabase()
    {
        var configs = new List<ConnectionConfig>
        {
            // 用户数据库
            new ConnectionConfig
            {
                ConfigId = "UserDb",
                ConnectionString = "server=.;database=UserDB;uid=sa;pwd=123",
                DbType = DbType.SqlServer,
                IsAutoCloseConnection = true
            },
            // 订单数据库
            new ConnectionConfig
            {
                ConfigId = "OrderDb",
                ConnectionString = "server=.;database=OrderDB;uid=sa;pwd=123",
                DbType = DbType.SqlServer,
                IsAutoCloseConnection = true
            },
            // 商品数据库
            new ConnectionConfig
            {
                ConfigId = "ProductDb",
                ConnectionString = "server=.;database=ProductDB;uid=sa;pwd=123",
                DbType = DbType.SqlServer,
                IsAutoCloseConnection = true
            }
        };
        
        return new SqlSugarScope(configs);
    }
}

// 使用多数据库
public class MultiDbService
{
    private readonly SqlSugarScope _db;
    
    public MultiDbService()
    {
        _db = MultiDatabaseConfig.CreateMultiDatabase();
    }
    
    // 从用户库查询
    public User GetUser(int userId)
    {
        return _db.GetConnection("UserDb")
            .Queryable<User>()
            .First(u => u.Id == userId);
    }
    
    // 从订单库查询
    public List<Order> GetOrders(int userId)
    {
        return _db.GetConnection("OrderDb")
            .Queryable<Order>()
            .Where(o => o.UserId == userId)
            .ToList();
    }
    
    // 从商品库查询
    public Product GetProduct(int productId)
    {
        return _db.GetConnection("ProductDb")
            .Queryable<Product>()
            .First(p => p.Id == productId);
    }
}

10.4.2 跨库查询

实现跨库关联查询:

public class CrossDatabaseQuery
{
    private readonly SqlSugarScope _db;
    
    // 跨库查询:查询订单及用户信息
    public List<OrderWithUserDto> GetOrdersWithUser()
    {
        // 方式1:分别查询后内存Join
        var orders = _db.GetConnection("OrderDb")
            .Queryable<Order>()
            .ToList();
        
        var userIds = orders.Select(o => o.UserId).Distinct().ToList();
        
        var users = _db.GetConnection("UserDb")
            .Queryable<User>()
            .Where(u => userIds.Contains(u.Id))
            .ToList();
        
        // 内存Join
        var result = from o in orders
                     join u in users on o.UserId equals u.Id
                     select new OrderWithUserDto
                     {
                         OrderNo = o.OrderNo,
                         Amount = o.Amount,
                         UserName = u.Name,
                         UserEmail = u.Email
                     };
        
        return result.ToList();
    }
    
    // 跨库事务
    public bool CreateOrderWithUserUpdate(Order order, User user)
    {
        try
        {
            // 使用分布式事务
            _db.BeginTran();
            
            // 更新用户信息
            _db.GetConnection("UserDb")
                .Updateable(user)
                .ExecuteCommand();
            
            // 创建订单
            _db.GetConnection("OrderDb")
                .Insertable(order)
                .ExecuteCommand();
            
            _db.CommitTran();
            return true;
        }
        catch
        {
            _db.RollbackTran();
            return false;
        }
    }
}

10.5 多租户架构

10.5.1 独立数据库模式

每个租户使用独立的数据库:

public class TenantConfig
{
    public int TenantId { get; set; }
    public string TenantName { get; set; }
    public string ConnectionString { get; set; }
}

public class TenantDatabaseProvider
{
    private readonly SqlSugarScope _scope;
    private readonly List<TenantConfig> _tenants;
    
    public TenantDatabaseProvider()
    {
        // 加载租户配置
        _tenants = LoadTenantConfigs();
        
        // 创建多租户数据库连接
        var configs = _tenants.Select(t => new ConnectionConfig
        {
            ConfigId = t.TenantId.ToString(),
            ConnectionString = t.ConnectionString,
            DbType = DbType.SqlServer,
            IsAutoCloseConnection = true
        }).ToList();
        
        _scope = new SqlSugarScope(configs);
    }
    
    public SqlSugarClient GetTenantDb(int tenantId)
    {
        return _scope.GetConnection(tenantId.ToString());
    }
    
    private List<TenantConfig> LoadTenantConfigs()
    {
        // 从配置文件或数据库加载租户配置
        return new List<TenantConfig>
        {
            new TenantConfig 
            { 
                TenantId = 1, 
                TenantName = "租户A",
                ConnectionString = "server=.;database=TenantA_DB;uid=sa;pwd=123"
            },
            new TenantConfig 
            { 
                TenantId = 2, 
                TenantName = "租户B",
                ConnectionString = "server=.;database=TenantB_DB;uid=sa;pwd=123"
            }
        };
    }
}

// 使用
public class TenantService
{
    private readonly TenantDatabaseProvider _provider;
    
    public List<Order> GetTenantOrders(int tenantId, int userId)
    {
        var db = _provider.GetTenantDb(tenantId);
        return db.Queryable<Order>()
            .Where(o => o.UserId == userId)
            .ToList();
    }
}

10.5.2 共享数据库模式

多个租户共享同一个数据库,通过TenantId区分:

// 实体类包含TenantId
public class Order
{
    [SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
    public int Id { get; set; }
    
    public int TenantId { get; set; } // 租户ID
    public string OrderNo { get; set; }
    public int UserId { get; set; }
    public decimal Amount { get; set; }
}

// 租户过滤器
public class TenantFilter
{
    private readonly SqlSugarClient _db;
    private int _currentTenantId;
    
    public TenantFilter(SqlSugarClient db)
    {
        _db = db;
        ConfigureGlobalFilter();
    }
    
    public void SetTenant(int tenantId)
    {
        _currentTenantId = tenantId;
    }
    
    private void ConfigureGlobalFilter()
    {
        // 配置全局查询过滤器
        _db.QueryFilter.Add(new TableFilterItem<Order>(
            it => it.TenantId == _currentTenantId));
        
        _db.QueryFilter.Add(new TableFilterItem<User>(
            it => it.TenantId == _currentTenantId));
        
        _db.QueryFilter.Add(new TableFilterItem<Product>(
            it => it.TenantId == _currentTenantId));
    }
}

// 使用租户过滤器
public class OrderService
{
    private readonly SqlSugarClient _db;
    private readonly TenantFilter _tenantFilter;
    
    public OrderService(SqlSugarClient db, TenantFilter tenantFilter)
    {
        _db = db;
        _tenantFilter = tenantFilter;
    }
    
    public List<Order> GetOrders(int tenantId)
    {
        // 设置当前租户
        _tenantFilter.SetTenant(tenantId);
        
        // 查询时自动过滤当前租户的数据
        return _db.Queryable<Order>().ToList();
    }
    
    public void AddOrder(int tenantId, Order order)
    {
        // 自动设置租户ID
        order.TenantId = tenantId;
        _db.Insertable(order).ExecuteCommand();
    }
}

10.5.3 租户隔离

实现完整的租户隔离机制:

public class TenantContext
{
    private static AsyncLocal<int> _tenantId = new AsyncLocal<int>();
    
    public static int CurrentTenantId
    {
        get => _tenantId.Value;
        set => _tenantId.Value = value;
    }
}

// AOP拦截器自动设置租户
public class TenantInterceptor
{
    public static void Configure(SqlSugarClient db)
    {
        // 插入时自动设置TenantId
        db.Aop.DataExecuting = (oldValue, entityInfo) =>
        {
            if (entityInfo.PropertyName == "TenantId")
            {
                entityInfo.SetValue(TenantContext.CurrentTenantId);
            }
        };
        
        // 查询时自动过滤
        db.QueryFilter.AddTableFilter<ITenant>(it => 
            it.TenantId == TenantContext.CurrentTenantId);
    }
}

// 租户接口
public interface ITenant
{
    int TenantId { get; set; }
}

// 实体实现租户接口
public class Order : ITenant
{
    public int Id { get; set; }
    public int TenantId { get; set; }
    public string OrderNo { get; set; }
}

// ASP.NET Core中间件
public class TenantMiddleware
{
    private readonly RequestDelegate _next;
    
    public TenantMiddleware(RequestDelegate next)
    {
        _next = next;
    }
    
    public async Task InvokeAsync(HttpContext context)
    {
        // 从请求头或Token中获取租户ID
        var tenantId = GetTenantIdFromRequest(context);
        TenantContext.CurrentTenantId = tenantId;
        
        await _next(context);
    }
    
    private int GetTenantIdFromRequest(HttpContext context)
    {
        // 从Header获取
        if (context.Request.Headers.TryGetValue("X-Tenant-Id", out var headerValue))
        {
            return int.Parse(headerValue);
        }
        
        // 从JWT Token获取
        var tenantClaim = context.User.FindFirst("TenantId");
        if (tenantClaim != null)
        {
            return int.Parse(tenantClaim.Value);
        }
        
        return 0;
    }
}

10.6 扩展性策略

// 数据迁移策略
public class DataMigrationService
{
    private readonly SqlSugarClient _sourceDb;
    private readonly SqlSugarClient _targetDb;
    
    // 数据迁移到新的分表
    public void MigrateToNewTable(DateTime start, DateTime end)
    {
        var sourceTableName = $"order_{start:yyyyMM}";
        var targetTableName = $"order_{end:yyyyMM}";
        
        // 创建新表
        _targetDb.DbMaintenance.CreateTable(targetTableName, 
            _sourceDb.DbMaintenance.GetTableInfoList(sourceTableName));
        
        // 批量迁移数据
        var pageSize = 10000;
        var pageIndex = 1;
        int totalCount = 0;
        
        do
        {
            var data = _sourceDb.Queryable<Order>()
                .AS(sourceTableName)
                .Where(o => o.CreateTime >= start && o.CreateTime < end)
                .ToPageList(pageIndex, pageSize, ref totalCount);
            
            if (data.Count > 0)
            {
                _targetDb.Insertable(data)
                    .AS(targetTableName)
                    .ExecuteCommand();
            }
            
            pageIndex++;
        } while ((pageIndex - 1) * pageSize < totalCount);
    }
    
    // 历史数据归档
    public void ArchiveHistoricalData(DateTime beforeDate)
    {
        var archiveDb = new SqlSugarClient(new ConnectionConfig
        {
            ConnectionString = "Archive Database Connection",
            DbType = DbType.SqlServer
        });
        
        // 查询需要归档的数据
        var data = _sourceDb.Queryable<Order>()
            .Where(o => o.CreateTime < beforeDate)
            .ToList();
        
        // 插入到归档库
        archiveDb.Insertable(data).ExecuteCommand();
        
        // 删除原数据
        _sourceDb.Deleteable<Order>()
            .Where(o => o.CreateTime < beforeDate)
            .ExecuteCommand();
    }
}

// 自动扩容策略
public class AutoScalingService
{
    // 监控表大小,自动分表
    public void MonitorAndSplit()
    {
        var tables = GetAllTables();
        
        foreach (var table in tables)
        {
            var rowCount = GetTableRowCount(table);
            var tableSize = GetTableSize(table);
            
            // 当记录数超过1000万或表大小超过10GB时分表
            if (rowCount > 10000000 || tableSize > 10 * 1024 * 1024 * 1024)
            {
                SplitTable(table);
            }
        }
    }
    
    private void SplitTable(string tableName)
    {
        // 实现分表逻辑
        Console.WriteLine($"表 {tableName} 需要分表");
    }
}

10.7 本章小结

本章深入讲解了SqlSugar的分表分库和多租户架构:

  1. 分表分库概念:理解了为什么需要分表分库,以及水平分表、垂直分表、垂直分库的区别
  2. 水平分表:掌握了使用SplitTable特性实现按时间、按范围的分表策略
  3. 自动路由:学会了配置分表路由规则和动态表名的使用
  4. 垂直分库:了解了如何配置多数据库连接和实现跨库查询
  5. 多租户架构:掌握了独立数据库和共享数据库两种多租户模式
  6. 租户隔离:实现了完整的租户数据隔离和安全机制
  7. 扩展性策略:学习了数据迁移、归档和自动扩容的实现方法

通过本章的学习,您应该能够设计和实现支持大规模数据和高并发的分布式数据库架构。在下一章中,我们将学习SqlSugar的AOP与日志监控功能,这对于系统的可维护性和问题排查至关重要。