Skip to content

Commit 00dae1b

Browse files
committed
解决 JOIN 副表包含 SQL 函数时没有返回 SQL 函数的执行结果以及未用上 SQL 缓存导致冗余 SQL 查询 #341;提升 JOIN 封装结果的性能
1 parent a804e75 commit 00dae1b

File tree

1 file changed

+146
-37
lines changed

1 file changed

+146
-37
lines changed

APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java

Lines changed: 146 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import java.util.List;
2626
import java.util.Map;
2727
import java.util.Map.Entry;
28+
import java.util.Objects;
2829
import java.util.Set;
2930

3031
import com.alibaba.fastjson.JSON;
@@ -267,39 +268,147 @@ public JSONObject execute(@NotNull SQLConfig config, boolean unknowType) throws
267268

268269
//<SELECT * FROM Comment WHERE momentId = '470', { id: 1, content: "csdgs" }>
269270
childMap = new HashMap<>(); //要存到cacheMap
271+
// Map<Integer, Join> columnIndexAndJoinMap = new HashMap<>(length);
272+
String lastTableName = null; // 默认就是主表 config.getTable();
273+
int lastViceTableStart = 0;
274+
int lastViceColumnStart = 0;
275+
Join lastJoin = null;
276+
// TODO String[] columnIndexAndTableMap = new String[length];
270277
// WHERE id = ? AND ... 或 WHERE ... AND id = ? 强制排序 remove 再 put,还是重新 getSQL吧
271278

272279

273-
boolean hasJoin = config.hasJoin();
274-
int viceColumnStart = length + 1; //第一个副表字段的index
280+
List<Join> joinList = config.getJoinList();
281+
boolean hasJoin = config.hasJoin() && joinList != null && ! joinList.isEmpty();
282+
283+
// 直接用数组存取更快 Map<Integer, Join> columnIndexAndJoinMap = isExplain || ! hasJoin ? null : new HashMap<>(length);
284+
Join[] columnIndexAndJoinMap = isExplain || ! hasJoin ? null : new Join[length];
285+
286+
// int viceColumnStart = length + 1; //第一个副表字段的index
275287
while (rs.next()) {
276288
index ++;
277289
Log.d(TAG, "\n\n<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n execute while (rs.next()){ index = " + index + "\n\n");
278290

279291
JSONObject item = new JSONObject(true);
280-
292+
boolean isMain = true;
293+
281294
for (int i = 1; i <= length; i++) {
282295

283296
// if (hasJoin && viceColumnStart > length && config.getSQLTable().equalsIgnoreCase(rsmd.getTableName(i)) == false) {
284297
// viceColumnStart = i;
285298
// }
286299

287300
// bugfix-修复非常规数据库字段,获取表名失败导致输出异常
288-
if (isExplain == false && hasJoin && viceColumnStart > length) {
289-
List<String> column = config.getColumn();
290-
String sqlTable = rsmd.getTableName(i);
291-
if (config.isClickHouse()&&(sqlTable.startsWith("`")||sqlTable.startsWith("\""))){
292-
sqlTable = sqlTable.substring(1,sqlTable.length()-1);
301+
Join curJoin = columnIndexAndJoinMap == null ? null : columnIndexAndJoinMap[i - 1]; // columnIndexAndJoinMap.get(i);
302+
303+
// 为什么 isExplain == false 不用判断?因为所有字段都在一张 Query Plan 表
304+
if (index <= 0 && hasJoin && ! isExplain) { // && viceColumnStart > length) {
305+
306+
SQLConfig curConfig = curJoin == null || ! curJoin.isSQLJoin() ? null : curJoin.getCacheConfig();
307+
List<String> curColumn = curConfig == null ? null : curConfig.getColumn();
308+
String sqlTable = curConfig == null ? null : curConfig.getSQLTable();
309+
310+
List<String> column = config.getColumn();
311+
int mainColumnSize = column == null ? 0 : column.size();
312+
boolean toFindJoin = mainColumnSize <= 0 || i > mainColumnSize; // 主表就不用找 JOIN 配置
313+
314+
if (StringUtil.isEmpty(sqlTable , true)) {
315+
if (toFindJoin) { // 在主表字段数量内的都归属主表
316+
sqlTable = rsmd.getTableName(i); // SQL 函数甚至部分字段都不返回表名,当然如果没传 @column 生成的 Table.* 则返回的所有字段都会带表名
317+
318+
if (StringUtil.isEmpty(sqlTable, true)) { // hasJoin 已包含这个判断 && joinList != null) {
319+
320+
int nextViceColumnStart = lastViceColumnStart; // 主表没有 @column 时会偏小 lastViceColumnStart
321+
for (int j = lastViceTableStart; j < joinList.size(); j++) { // 查找副表 @column,定位字段所在表
322+
Join join = joinList.get(j);
323+
SQLConfig cfg = join == null || ! join.isSQLJoin() ? null : join.getJoinConfig();
324+
List<String> c = cfg == null ? null : cfg.getColumn();
325+
326+
nextViceColumnStart += (
327+
c != null && ! c.isEmpty() ? c.size()
328+
: (Objects.equals(sqlTable, lastTableName) || sqlTable.equalsIgnoreCase(lastTableName) ? 1 : 0)
329+
);
330+
if (i < nextViceColumnStart) {
331+
sqlTable = cfg.getSQLTable();
332+
lastViceTableStart = j; // 避免后面的空 @column 表内字段被放到之前的空 @column 表
333+
334+
curJoin = join;
335+
curConfig = cfg;
336+
curColumn = c;
337+
338+
toFindJoin = false;
339+
isMain = false;
340+
break;
341+
}
342+
}
343+
}
344+
345+
// 没有 @column,仍然定位不了,用前一个 table 名。FIXME 如果刚好某个表内第一个字段是就是 SQL 函数?
346+
if (StringUtil.isEmpty(sqlTable, true)) {
347+
sqlTable = lastTableName;
348+
toFindJoin = false;
349+
}
350+
}
293351
}
294-
if (column != null && column.isEmpty() == false) {
295-
viceColumnStart = column.size() + 1;
352+
else if (config.isClickHouse() && (sqlTable.startsWith("`") || sqlTable.startsWith("\""))){
353+
sqlTable = sqlTable.substring(1, sqlTable.length() - 1);
296354
}
297-
else if (config.getSQLTable().equalsIgnoreCase(sqlTable) == false) {
298-
viceColumnStart = i;
355+
356+
if ((sqlTable == null && lastTableName != null) || (sqlTable != null && ! sqlTable.equalsIgnoreCase(lastTableName))) {
357+
lastTableName = sqlTable;
358+
lastViceColumnStart = i;
359+
360+
if (toFindJoin) { // 找到对应的副表 JOIN 配置
361+
for (int j = lastViceTableStart; j < joinList.size(); j++) { // 查找副表 @column,定位字段所在表
362+
Join join = joinList.get(j);
363+
SQLConfig cfg = join == null || ! join.isSQLJoin() ? null : join.getJoinConfig();
364+
365+
if (cfg != null && sqlTable != null && sqlTable.equalsIgnoreCase(cfg.getSQLTable())) {
366+
lastViceTableStart = j; // 避免后面的空 @column 表内字段被放到之前的空 @column 表
367+
368+
curJoin = join;
369+
curConfig = cfg;
370+
curColumn = curConfig == null ? null : curConfig.getColumn();
371+
372+
isMain = false;
373+
break;
374+
}
375+
}
376+
}
299377
}
378+
379+
if (isMain) {
380+
lastViceColumnStart ++;
381+
}
382+
else {
383+
if (curJoin == null) {
384+
curJoin = lastJoin;
385+
}
386+
else {
387+
lastJoin = curJoin;
388+
}
389+
390+
if (curColumn == null) {
391+
curConfig = curJoin == null || ! curJoin.isSQLJoin() ? null : curJoin.getJoinConfig();
392+
curColumn = curConfig == null ? null : curConfig.getColumn();
393+
}
394+
395+
// 解决后面的表内 SQL 函数被放到之前的空 @column 表
396+
if (curColumn == null || curColumn.isEmpty()) {
397+
lastViceColumnStart ++;
398+
}
399+
}
400+
401+
columnIndexAndJoinMap[i - 1] = curJoin; // columnIndexAndJoinMap.put(i, curJoin); // TODO columnIndexAndTableMap[i] = sqlTable 提速?
402+
403+
// if (column != null && column.isEmpty() == false) {
404+
// viceColumnStart = column.size() + 1;
405+
// }
406+
// else if (config.getSQLTable().equalsIgnoreCase(sqlTable) == false) {
407+
// viceColumnStart = i;
408+
// }
300409
}
301410

302-
item = onPutColumn(config, rs, rsmd, index, item, i, isExplain == false && hasJoin && i >= viceColumnStart ? childMap : null);
411+
item = onPutColumn(config, rs, rsmd, index, item, i, curJoin, childMap); // isExplain == false && hasJoin && i >= viceColumnStart ? childMap : null);
303412
}
304413

305414
resultList = onPutTable(config, rs, rsmd, resultList, index, item);
@@ -391,21 +500,21 @@ protected void executeAppJoin(SQLConfig config, List<JSONObject> resultList, Map
391500
SQLConfig jc;
392501
SQLConfig cc;
393502

394-
for (Join j : joinList) {
395-
if (j.isAppJoin() == false) {
503+
for (Join join : joinList) {
504+
if (join.isAppJoin() == false) {
396505
Log.i(TAG, "executeAppJoin for (Join j : joinList) >> j.isAppJoin() == false >> continue;");
397506
continue;
398507
}
399508

400-
cc = j.getCacheConfig(); //这里用config改了getSQL后再还原很麻烦,所以提前给一个config2更好
509+
cc = join.getCacheConfig(); //这里用config改了getSQL后再还原很麻烦,所以提前给一个config2更好
401510
if (cc == null) {
402511
if (Log.DEBUG) {
403512
throw new NullPointerException("服务器内部错误, executeAppJoin cc == null ! 导致不能缓存 @ APP JOIN 的副表数据!");
404513
}
405514
continue;
406515
}
407516

408-
jc = j.getJoinConfig();
517+
jc = join.getJoinConfig();
409518

410519
//取出 "id@": "@/User/userId" 中所有 userId 的值
411520
List<Object> targetValueList = new ArrayList<>();
@@ -414,7 +523,7 @@ protected void executeAppJoin(SQLConfig config, List<JSONObject> resultList, Map
414523

415524
for (int i = 0; i < resultList.size(); i++) {
416525
mainTable = resultList.get(i);
417-
targetValue = mainTable == null ? null : mainTable.get(j.getTargetKey());
526+
targetValue = mainTable == null ? null : mainTable.get(join.getTargetKey());
418527

419528
if (targetValue != null && targetValueList.contains(targetValue) == false) {
420529
targetValueList.add(targetValue);
@@ -423,8 +532,8 @@ protected void executeAppJoin(SQLConfig config, List<JSONObject> resultList, Map
423532

424533

425534
//替换为 "id{}": [userId1, userId2, userId3...]
426-
jc.putWhere(j.getOriginKey(), null, false); // remove orginKey
427-
jc.putWhere(j.getKey() + "{}", targetValueList, true); // add orginKey{}
535+
jc.putWhere(join.getOriginKey(), null, false); // remove orginKey
536+
jc.putWhere(join.getKey() + "{}", targetValueList, true); // add orginKey{}
428537

429538
jc.setMain(true).setPreparedValueList(new ArrayList<>());
430539

@@ -462,7 +571,7 @@ protected void executeAppJoin(SQLConfig config, List<JSONObject> resultList, Map
462571

463572
for (int i = 1; i <= length; i++) {
464573

465-
result = onPutColumn(jc, rs, rsmd, index, result, i, null);
574+
result = onPutColumn(jc, rs, rsmd, index, result, i, null, null);
466575
}
467576

468577
//每个 result 都要用新的 SQL 来存 childResultMap = onPutTable(config, rs, rsmd, childResultMap, index, result);
@@ -471,7 +580,7 @@ protected void executeAppJoin(SQLConfig config, List<JSONObject> resultList, Map
471580
+ "\n >>>>>>>>>>>>>>>>>>>>>>>>>>> \n\n");
472581

473582
//缓存到 childMap
474-
cc.putWhere(j.getKey(), result.get(j.getKey()), true);
583+
cc.putWhere(join.getKey(), result.get(join.getKey()), true);
475584
cacheSql = cc.getSQL(false);
476585
childMap.put(cacheSql, result);
477586

@@ -512,7 +621,7 @@ protected void executeAppJoin(SQLConfig config, List<JSONObject> resultList, Map
512621
* @throws Exception
513622
*/
514623
protected JSONObject onPutColumn(@NotNull SQLConfig config, @NotNull ResultSet rs, @NotNull ResultSetMetaData rsmd
515-
, final int tablePosition, @NotNull JSONObject table, final int columnIndex, Map<String, JSONObject> childMap) throws Exception {
624+
, final int tablePosition, @NotNull JSONObject table, final int columnIndex, Join join, Map<String, JSONObject> childMap) throws Exception {
516625

517626
if (isHideColumn(config, rs, rsmd, tablePosition, table, columnIndex, childMap)) {
518627
Log.i(TAG, "onPutColumn isHideColumn(config, rs, rsmd, tablePosition, table, columnIndex, childMap) >> return table;");
@@ -524,40 +633,40 @@ protected JSONObject onPutColumn(@NotNull SQLConfig config, @NotNull ResultSet r
524633
// int dotIndex = lable.indexOf(".");
525634
String lable = getKey(config, rs, rsmd, tablePosition, table, columnIndex, childMap);
526635

527-
String childTable = childMap == null ? null : rsmd.getTableName(columnIndex); //dotIndex < 0 ? null : lable.substring(0, dotIndex);
636+
// String childTable = childMap == null ? null : sqlTableName; // rsmd.getTableName(columnIndex); //dotIndex < 0 ? null : lable.substring(0, dotIndex);
528637

529638
JSONObject finalTable = null;
530639
String childSql = null;
531-
SQLConfig childConfig = null;
532-
533-
if (childTable == null) {
640+
641+
SQLConfig childConfig = join == null || join.isSQLJoin() == false ? null : join.getCacheConfig();
642+
if (childConfig == null) {
534643
finalTable = table;
535644
}
536645
else {
537646
// lable = column;
538647

539648
//<sql, Table>
540649

541-
List<Join> joinList = config.getJoinList();
542-
if (joinList != null) {
543-
for (Join j : joinList) {
544-
childConfig = j.isAppJoin() ? null : j.getCacheConfig(); //这里用config改了getSQL后再还原很麻烦,所以提前给一个config2更好
650+
// List<Join> joinList = config.getJoinList();
651+
// if (joinList != null) {
652+
// for (Join j : joinList) {
653+
// childConfig = j.isAppJoin() ? null : j.getCacheConfig(); //这里用config改了getSQL后再还原很麻烦,所以提前给一个config2更好
545654

546655
// FIXME 副表的 SQL 函数,甚至普通字段都可能从 rsmd.getTableName(columnIndex) 拿到 ""
547-
if (childConfig != null && childTable.equalsIgnoreCase(childConfig.getSQLTable())) {
656+
// if (childConfig != null && childTable.equalsIgnoreCase(childConfig.getSQLTable())) {
548657

549-
childConfig.putWhere(j.getKey(), table.get(j.getTargetKey()), true);
658+
childConfig.putWhere(join.getKey(), table.get(join.getTargetKey()), true);
550659
childSql = childConfig.getSQL(false);
551660

552661
if (StringUtil.isEmpty(childSql, true)) {
553662
return table;
554663
}
555664

556665
finalTable = (JSONObject) childMap.get(childSql);
557-
break;
558-
}
559-
}
560-
}
666+
// break;
667+
// }
668+
// }
669+
// }
561670

562671
}
563672

0 commit comments

Comments
 (0)