记一些分库带来的查询问题的解决方案
问题
数据库太大的时候,经常会出现拆库拆表的情况。这样当我们需要数据的时候,需要从一系列表(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