文章

记一些分库带来的查询问题的解决方案

问题

数据库太大的时候,经常会出现拆库拆表的情况。这样当我们需要数据的时候,需要从一系列表(tab_xxx_时间tab_xxx_序号)中进行select操作。这种操作是比较麻烦的。虽然有很多数据库的中间件、框架可以提供便捷的分表联合查询,但是作为开发人员还是应该研究下这个问题的。

一些思路

首先select并不能在表名处使用%通配符(mysql不行,Google cloud可以)。

因此需要将问题拆分为两个部分。

首先是如何获得究竟要到实例的哪些表里面去select。主要有两个思路

  • 使用以下语句select TABLE_NAME from information_schema.TABLES where TABLE_NAME like 'tab_app_log%';
  • 如果需要被查询的表是,数量有限的水平拆表的产物。这个拆表逻辑一般是基于mod的hash。那我们已知所有的表名。

之后需要解决如何执行sql查询。这里主要有四种方案

  • 使用存储过程进行拼装。因为存储过程是一种面向过程的语言,所以实现起来比较方便,有两种实现方式

    • select所有表名进入列表,对列表遍历查询,每次迭代将查询结果送进列表,最后将列表里面的所有结果select作为返回。代码比较简单就不贴了,但是效率比较低。

    • 直接在存储过程中使用字符串处理函数,使用union拼接处一个很长的语句执行。代码如下(这个看版本,mysql不一定跑的通)

      declare @sql varchar(max)
      set @sql = ''
      
      select @sql = @sql + case len(@sql) when 0 then '' else ' UNION ALL ' end + '
          SELECT * FROM [' + table_name + ']'
      from
          information_schema.tables where table_name like 'TABLE0%'
      
      exec (@sql)
      
    • 如果表数很少的话手动拼接执行

  • 使用套接sql查询,mysql不支持from后面的表名使用这样的语法,因此放弃。但是有些sql实现方式可以的。

  • 直接在外层使用高级语言或拆分多个select执行或使用union拼接,表名如果不已知的话还要select一轮。

最佳实现

这些方法要么慢、要么麻烦、要么自动化不够、要么不通用。实际上我们可以灵活使用识图功能。每一次分表时,更改视图(view),将新表union进视图,再从视图中查询,这个最简单,我称为最佳实践。有些分表中间件、框架就是这么操作的。

License:  CC BY 4.0