22
33/**
44 * 根据时间同构分表的查询类
5+ * @package app\common\library
56 * @author LIUJIAN <coder.keda@gmail.com>
67 */
78class ShardingQuery
@@ -19,13 +20,25 @@ class ShardingQuery
1920 * 根据顺序查询
2021 * @var array
2122 */
22- public $ tables ;
23+ public $ table ;
2324
2425 /**
25- * 查询语句
26+ * 字段
2627 * @var string
2728 */
28- public $ sql ;
29+ public $ field ;
30+
31+ /**
32+ * 条件
33+ * @var string
34+ */
35+ public $ where ;
36+
37+ /**
38+ * 排序
39+ * @var string
40+ */
41+ public $ order ;
2942
3043 /**
3144 * 限制数
@@ -40,24 +53,63 @@ class ShardingQuery
4053 public $ offset ;
4154
4255 /**
43- * 数据表的通配符
44- * @var string
56+ * 统计
57+ * @var array
4558 */
46- protected static $ tableSymbol = ' {table} ' ;
59+ protected $ stats ;
4760
4861 /**
49- * ShardingSelect constructor.
50- * @param array $tables
51- * @param callable $callback
52- * @param string $sql
62+ * ShardingQuery constructor.
63+ * @param array $config
5364 */
54- public function __construct (callable $ callback , array $ tables , string $ sql , int $ limit , int $ offset )
65+ public function __construct (array $ config )
5566 {
56- $ this ->callback = $ callback ;
57- $ this ->tables = $ tables ;
58- $ this ->sql = $ sql ;
59- $ this ->limit = $ limit ;
60- $ this ->offset = $ offset ;
67+ foreach ($ config as $ key => $ value ) {
68+ switch ($ key ) {
69+ case 'callback ' :
70+ if (!is_callable ($ value )) {
71+ throw new \RuntimeException ("'callback' is not a callable type. " );
72+ }
73+ $ this ->$ key = $ value ;
74+ break ;
75+ case 'table ' :
76+ if (!is_array ($ value )) {
77+ throw new \RuntimeException ("'table' is not a array type. " );
78+ }
79+ $ this ->$ key = $ value ;
80+ break ;
81+ case 'field ' :
82+ if (!is_string ($ value )) {
83+ throw new \RuntimeException ("'field' is not a string type. " );
84+ }
85+ $ this ->$ key = $ value ;
86+ break ;
87+ case 'where ' :
88+ if (!is_string ($ value )) {
89+ throw new \RuntimeException ("'where' is not a string type. " );
90+ }
91+ $ this ->$ key = $ value ;
92+ break ;
93+ case 'order ' :
94+ if (!is_string ($ value )) {
95+ throw new \RuntimeException ("'order' is not a string type. " );
96+ }
97+ $ this ->$ key = $ value ;
98+ break ;
99+ case 'limit ' :
100+ if (!is_int ($ value )) {
101+ throw new \RuntimeException ("'limit' is not a int type. " );
102+ }
103+ $ this ->$ key = $ value ;
104+ break ;
105+ case 'offset ' :
106+ if (!is_int ($ value )) {
107+ throw new \RuntimeException ("'offset' is not a int type. " );
108+ }
109+ $ this ->$ key = $ value ;
110+ break ;
111+ }
112+ }
61113 }
62114
63115 /**
@@ -66,28 +118,112 @@ public function __construct(callable $callback, array $tables, string $sql, int
66118 */
67119 public function select ()
68120 {
69- $ data = [];
70- foreach ($ this ->tables as $ num => $ table ) {
71- if (count ($ data ) < $ this ->limit ) {
72- $ limit = $ this ->limit ;
73- $ offset = $ this ->offset ;
74- if ($ num > 0 ) {
75- $ limit = $ this ->limit - count ($ data );
76- $ offset = 0 ;
77- }
78- $ sql = "{$ this ->sql } LIMIT {$ limit } OFFSET {$ offset }" ;
79- $ sql = str_replace (static ::$ tableSymbol , $ table , $ sql );
80- $ result = call_user_func ($ this ->callback , $ sql );
81- if (empty ($ result )) {
82- return $ data ;
83- }
84- $ data = array_merge ($ data , $ result );
121+ $ this ->stats = $ this ->stats ($ this ->table );
122+ $ range = $ this ->range ($ this ->stats );
123+ $ data = [];
124+ foreach ($ range as $ tableName => $ item ) {
125+ $ sql = "SELECT {$ this ->field } FROM ` {$ tableName }` " ;
126+ if (!empty ($ this ->where )) {
127+ $ sql .= " WHERE {$ this ->where }" ;
85128 }
86- if (count ( $ data ) >= $ this ->limit ) {
87- return $ data ;
129+ if (! empty ( $ this ->order ) ) {
130+ $ sql .= " ORDER BY { $ this -> order }" ;
88131 }
132+ $ sql = "{$ sql } LIMIT {$ item ['limit ' ]} OFFSET {$ item ['offset ' ]}" ;
133+ $ result = call_user_func ($ this ->callback , $ sql );
134+ $ data = array_merge ($ data , $ result );
89135 }
90136 return $ data ;
91137 }
92138
139+ /**
140+ * 获取表的统计信息
141+ * @param $table
142+ * @return array
143+ */
144+ protected function stats ($ table )
145+ {
146+ $ end = 0 ;
147+ $ stats = [];
148+ foreach ($ table as $ num => $ tableName ) {
149+ $ sql = "SELECT COUNT(*) FROM ` {$ tableName }` " ;
150+ if (!empty ($ this ->where )) {
151+ $ sql .= " WHERE {$ this ->where }" ;
152+ }
153+ $ result = call_user_func ($ this ->callback , $ sql );
154+ $ first = array_pop ($ result );
155+ $ count = array_pop ($ first );
156+ $ start = $ end ;
157+ $ end += $ count ;
158+ $ stats [$ tableName ] = [
159+ 'start ' => $ start ,
160+ 'end ' => $ end ,
161+ ];
162+ }
163+ return $ stats ;
164+ }
165+
166+ /**
167+ * 获取要提取的表数据范围
168+ * @param $stats
169+ * @return array
170+ */
171+ protected function range ($ stats )
172+ {
173+ $ limit = $ this ->limit ;
174+ $ offset = $ this ->offset ;
175+ $ start = $ offset ;
176+ $ end = $ offset + $ limit ;
177+ $ tables = [];
178+ foreach ($ stats as $ table => $ item ) {
179+ $ before = $ item ['start ' ] <= $ start && $ item ['end ' ] >= $ start ? true : false ;
180+ $ center = $ item ['start ' ] > $ start && $ item ['end ' ] < $ end ? true : false ;
181+ $ after = $ item ['start ' ] <= $ end && $ item ['end ' ] >= $ end ? true : false ;
182+ if ($ before && $ after ) {
183+ $ tables [$ table ] = [
184+ 'offset ' => $ start - $ item ['start ' ],
185+ 'limit ' => $ end - $ start ,
186+ ];
187+ continue ;
188+ }
189+ if ($ before ) {
190+ $ tables [$ table ] = [
191+ 'offset ' => $ start - $ item ['start ' ],
192+ 'limit ' => $ item ['end ' ] - $ start ,
193+ ];
194+ if ($ tables [$ table ]['limit ' ] == 0 ) {
195+ unset($ tables [$ table ]);
196+ }
197+ continue ;
198+ }
199+ if ($ after ) {
200+ $ tables [$ table ] = [
201+ 'offset ' => 0 ,
202+ 'limit ' => $ end - $ item ['start ' ],
203+ ];
204+ continue ;
205+ }
206+ if ($ center ) {
207+ $ tables [$ table ] = [
208+ 'offset ' => 0 ,
209+ 'limit ' => $ item ['end ' ] - $ item ['start ' ],
210+ ];
211+ continue ;
212+ }
213+ }
214+ return $ tables ;
215+ }
216+
217+ /**
218+ * 获取数据总数
219+ * @return int
220+ */
221+ public function count ()
222+ {
223+ $ stats = $ this ->stats ;
224+ $ last = array_pop ($ stats );
225+ $ number = array_pop ($ last );
226+ return $ number ?: 0 ;
227+ }
228+
93229}
0 commit comments