Skip to content

Commit 688a552

Browse files
alismanclaude
andcommitted
Comprehensive ArrayTypeHandler optimization for ClickHouse JDBC performance
Apply ArrayTypeHandler optimization strategy across all high-priority MyBatis mappers to dramatically improve ClickHouse JDBC performance by reducing prepared statement parameter overhead. SqlUtils Enhancements: - Add listToArray() utility method to convert List<String> to String[] for ArrayTypeHandler - Extend combineStudyAndPatientIds() usage for multi-study query optimization Optimized MyBatis Mappers (11 files): - ClinicalAttributeMapper.xml - clinical attribute count queries with sample IDs - ClinicalDataMapper.xml - sample and patient clinical data queries - ClinicalEventMapper.xml - clinical events by sample and patient IDs - CopyNumberSegmentMapper.xml - copy number segment queries - DiscreteCopyNumberMapper.xml - discrete copy number queries - MutationMapper.xml - mutation queries with sample/profile pairs - NamespaceMapper.xml - sample ID namespace queries - SampleMapper.xml - sample queries with study/sample and study/patient pairs - StructuralVariantMapper.xml - structural variant queries - TreatmentMapper.xml - treatment sample ID queries Optimization Strategy Applied: - Single-study queries: Use <bind> + ArrayTypeHandler for direct List→Array conversion - Multi-study queries: Use SqlUtils.combineStudyAndPatientIds() with CONCAT matching - Replace foreach loops generating multiple prepared statement parameters - Use proper <bind> elements to avoid MyBatis parameter binding errors Performance Impact: - Reduces prepared statement parameters from potentially thousands to single arrays - Follows same proven optimization pattern from PatientMapper (commit 2e2ec22) - Maintains security through proper parameter binding - Significant improvement for ClickHouse JDBC connections 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
1 parent 3fd4662 commit 688a552

File tree

11 files changed

+112
-57
lines changed

11 files changed

+112
-57
lines changed

src/main/java/org/cbioportal/legacy/persistence/mybatis/util/SqlUtils.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,18 @@ public static String[] combineStudyAndPatientIds(List<String> studyIds, List<Str
2727

2828
return combinedKeys;
2929
}
30+
31+
/**
32+
* Converts a List of strings to a String array for use with ArrayTypeHandler. ArrayTypeHandler
33+
* requires Java arrays, not ArrayList objects.
34+
*
35+
* @param list List of strings to convert
36+
* @return Array of strings
37+
*/
38+
public static String[] listToArray(List<String> list) {
39+
if (list == null) {
40+
return null;
41+
}
42+
return list.toArray(new String[0]);
43+
}
3044
}

src/main/resources/org/cbioportal/legacy/persistence/mybatis/ClinicalAttributeMapper.xml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,10 @@
3636
</if>
3737
<if test="sampleIds != null">
3838
<if test="@java.util.Arrays@stream(studyIds.toArray()).distinct().count() == 1">
39+
<bind name="sampleArray" value="@org.cbioportal.legacy.persistence.mybatis.util.SqlUtils@listToArray(sampleIds)" />
3940
cancer_study.cancer_study_identifier = #{studyIds[0]} AND
4041
sample.stable_id IN (
41-
#{sampleIds, typeHandler=org.apache.ibatis.type.ArrayTypeHandler}
42+
#{sampleArray, typeHandler=org.apache.ibatis.type.ArrayTypeHandler}
4243
)
4344
</if>
4445
<if test="@java.util.Arrays@stream(studyIds.toArray()).distinct().count() > 1">

src/main/resources/org/cbioportal/legacy/persistence/mybatis/ClinicalDataMapper.xml

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -65,13 +65,17 @@
6565
<if test="sampleIds != null">
6666
<choose>
6767
<when test="studyIds.stream().distinct().count() == 1">
68+
<bind name="sampleArray" value="@org.cbioportal.legacy.persistence.mybatis.util.SqlUtils@listToArray(sampleIds)" />
6869
cancer_study.cancer_study_identifier = #{studyIds[0]} AND
69-
sample.stable_id IN
70-
<foreach item="item" collection="sampleIds" open="(" separator="," close=")">#{item}</foreach>
70+
sample.stable_id IN (
71+
#{sampleArray, typeHandler=org.apache.ibatis.type.ArrayTypeHandler}
72+
)
7173
</when>
7274
<otherwise>
73-
(cancer_study.cancer_study_identifier, sample.stable_id) IN
74-
<foreach index="i" collection="sampleIds" open="(" separator="," close=")">(#{studyIds[${i}]},#{sampleIds[${i}]})</foreach>
75+
<bind name="sampleUniqueKeys" value="@org.cbioportal.legacy.persistence.mybatis.util.SqlUtils@combineStudyAndPatientIds(studyIds, sampleIds)" />
76+
CONCAT(cancer_study.cancer_study_identifier, ':', sample.stable_id) IN (
77+
#{sampleUniqueKeys, typeHandler=org.apache.ibatis.type.ArrayTypeHandler}
78+
)
7579
</otherwise>
7680
</choose>
7781
</if>
@@ -90,13 +94,17 @@
9094
<if test="patientIds != null">
9195
<choose>
9296
<when test="studyIds.stream().distinct().count() == 1">
97+
<bind name="patientArray" value="@org.cbioportal.legacy.persistence.mybatis.util.SqlUtils@listToArray(patientIds)" />
9398
cancer_study.cancer_study_identifier = #{studyIds[0]} AND
94-
patient.stable_id IN
95-
<foreach item="item" collection="patientIds" open="(" separator="," close=")">#{item}</foreach>
99+
patient.stable_id IN (
100+
#{patientArray, typeHandler=org.apache.ibatis.type.ArrayTypeHandler}
101+
)
96102
</when>
97103
<otherwise>
98-
(cancer_study.cancer_study_identifier, patient.stable_id) IN
99-
<foreach index="i" collection="patientIds" open="(" separator="," close=")">(#{studyIds[${i}]},#{patientIds[${i}]})</foreach>
104+
<bind name="patientUniqueKeys" value="@org.cbioportal.legacy.persistence.mybatis.util.SqlUtils@combineStudyAndPatientIds(studyIds, patientIds)" />
105+
CONCAT(cancer_study.cancer_study_identifier, ':', patient.stable_id) IN (
106+
#{patientUniqueKeys, typeHandler=org.apache.ibatis.type.ArrayTypeHandler}
107+
)
100108
</otherwise>
101109
</choose>
102110
</if>

src/main/resources/org/cbioportal/legacy/persistence/mybatis/ClinicalEventMapper.xml

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -111,15 +111,17 @@
111111
</if>
112112
<if test="sampleIds != null">
113113
<if test="@java.util.Arrays@stream(studyIds.toArray()).distinct().count() == 1">
114+
<bind name="sampleArray" value="@org.cbioportal.legacy.persistence.mybatis.util.SqlUtils@listToArray(sampleIds)" />
114115
cancer_study.cancer_study_identifier = #{studyIds[0]} AND
115-
sample.stable_id IN
116-
<foreach item="item" collection="sampleIds" open="(" separator="," close=")">#{item}</foreach>
116+
sample.stable_id IN (
117+
#{sampleArray, typeHandler=org.apache.ibatis.type.ArrayTypeHandler}
118+
)
117119
</if>
118120
<if test="@java.util.Arrays@stream(studyIds.toArray()).distinct().count() > 1">
119-
cancer_study.cancer_study_identifier IN
120-
<foreach item="item" collection="@java.util.Arrays@stream(studyIds.toArray()).distinct().collect(@java.util.stream.Collectors@toList())" open="(" separator="," close=")">#{item}</foreach>
121-
AND (cancer_study.cancer_study_identifier, sample.stable_id) IN
122-
<foreach index="i" collection="sampleIds" open="(" separator="," close=")">(#{studyIds[${i}]},#{sampleIds[${i}]})</foreach>
121+
<bind name="sampleUniqueKeys" value="@org.cbioportal.legacy.persistence.mybatis.util.SqlUtils@combineStudyAndPatientIds(studyIds, sampleIds)" />
122+
CONCAT(cancer_study.cancer_study_identifier, ':', sample.stable_id) IN (
123+
#{sampleUniqueKeys, typeHandler=org.apache.ibatis.type.ArrayTypeHandler}
124+
)
123125
</if>
124126
</if>
125127
</where>
@@ -146,13 +148,17 @@
146148
</if>
147149
<if test="patientIds != null">
148150
<if test="@java.util.Arrays@stream(patientIds.toArray()).distinct().count() == 1">
151+
<bind name="patientArray" value="@org.cbioportal.legacy.persistence.mybatis.util.SqlUtils@listToArray(patientIds)" />
149152
cancer_study.cancer_study_identifier = #{studyIds[0]} AND
150-
patient.stable_id IN
151-
<foreach item="item" collection="patientIds" open="(" separator="," close=")">#{item}</foreach>
153+
patient.stable_id IN (
154+
#{patientArray, typeHandler=org.apache.ibatis.type.ArrayTypeHandler}
155+
)
152156
</if>
153157
<if test="@java.util.Arrays@stream(patientIds.toArray()).distinct().count() > 1">
154-
(cancer_study.cancer_study_identifier, patient.stable_id) IN
155-
<foreach index="i" collection="patientIds" open="(" separator="," close=")">(#{studyIds[${i}]},#{patientIds[${i}]})</foreach>
158+
<bind name="patientUniqueKeys" value="@org.cbioportal.legacy.persistence.mybatis.util.SqlUtils@combineStudyAndPatientIds(studyIds, patientIds)" />
159+
CONCAT(cancer_study.cancer_study_identifier, ':', patient.stable_id) IN (
160+
#{patientUniqueKeys, typeHandler=org.apache.ibatis.type.ArrayTypeHandler}
161+
)
156162
</if>
157163
</if>
158164
<if test="!clinicalEvents.isEmpty()">

src/main/resources/org/cbioportal/legacy/persistence/mybatis/CopyNumberSegmentMapper.xml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,10 @@
2626
<sql id="where">
2727
<where>
2828
<if test="sampleIds != null and !sampleIds.isEmpty()">
29-
(cancer_study.cancer_study_identifier, sample.stable_id) IN
30-
<foreach index="i" collection="sampleIds" open="(" separator="," close=")">(#{studyIds[${i}]},#{sampleIds[${i}]})</foreach>
29+
<bind name="sampleUniqueKeys" value="@org.cbioportal.legacy.persistence.mybatis.util.SqlUtils@combineStudyAndPatientIds(studyIds, sampleIds)" />
30+
CONCAT(cancer_study.cancer_study_identifier, ':', sample.stable_id) IN (
31+
#{sampleUniqueKeys, typeHandler=org.apache.ibatis.type.ArrayTypeHandler}
32+
)
3133
</if>
3234
</where>
3335
</sql>

src/main/resources/org/cbioportal/legacy/persistence/mybatis/DiscreteCopyNumberMapper.xml

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,13 +77,17 @@
7777
<sql id="whereInMultipleMolecularProfiles">
7878
<where>
7979
<if test="@java.util.Arrays@stream(molecularProfileIds.toArray()).distinct().count() == 1">
80+
<bind name="sampleArray" value="@org.cbioportal.legacy.persistence.mybatis.util.SqlUtils@listToArray(sampleIds)" />
8081
genetic_profile.stable_id = #{molecularProfileIds[0]} AND
81-
sample.stable_id IN
82-
<foreach item="item" collection="sampleIds" open="(" separator="," close=")">#{item}</foreach>
82+
sample.stable_id IN (
83+
#{sampleArray, typeHandler=org.apache.ibatis.type.ArrayTypeHandler}
84+
)
8385
</if>
8486
<if test="@java.util.Arrays@stream(molecularProfileIds.toArray()).distinct().count() > 1">
85-
(sample.stable_id, genetic_profile.stable_id) IN
86-
<foreach index="i" collection="sampleIds" open="(" separator="," close=")">(#{sampleIds[${i}]},#{molecularProfileIds[${i}]})</foreach>
87+
<bind name="sampleProfileKeys" value="@org.cbioportal.legacy.persistence.mybatis.util.SqlUtils@combineStudyAndPatientIds(sampleIds, molecularProfileIds)" />
88+
CONCAT(sample.stable_id, ':', genetic_profile.stable_id) IN (
89+
#{sampleProfileKeys, typeHandler=org.apache.ibatis.type.ArrayTypeHandler}
90+
)
8791
</if>
8892
<if test="_parameter.containsKey('entrezGeneIds') and entrezGeneIds != null and !entrezGeneIds.isEmpty()">
8993
AND cna_event.entrez_gene_id IN

src/main/resources/org/cbioportal/legacy/persistence/mybatis/MutationMapper.xml

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -124,15 +124,21 @@
124124
INNER JOIN genetic_profile ON patient.cancer_study_id = genetic_profile.cancer_study_id
125125
WHERE
126126
<if test="@java.util.Arrays@stream(molecularProfileIds.toArray()).distinct().count() == 1">
127+
<bind name="sampleArray" value="@org.cbioportal.legacy.persistence.mybatis.util.SqlUtils@listToArray(sampleIds)" />
127128
genetic_profile.stable_id = #{molecularProfileIds[0]} AND
128-
sample.stable_id IN
129-
<foreach item="item" collection="sampleIds" open="(" separator="," close=")">#{item}</foreach>
129+
sample.stable_id IN (
130+
#{sampleArray, typeHandler=org.apache.ibatis.type.ArrayTypeHandler}
131+
)
130132
</if>
131133
<if test="@java.util.Arrays@stream(molecularProfileIds.toArray()).distinct().count() > 1">
132-
(sample.stable_id, genetic_profile.stable_id) IN
133-
<foreach index="i" collection="sampleIds" open="(" separator="," close=")">(#{sampleIds[${i}]},#{molecularProfileIds[${i}]})</foreach>
134-
AND genetic_profile.stable_id IN
135-
<foreach item="item" collection="molecularProfileIds" open="(" separator="," close=")">#{item}</foreach>
134+
<bind name="sampleProfileKeys" value="@org.cbioportal.legacy.persistence.mybatis.util.SqlUtils@combineStudyAndPatientIds(sampleIds, molecularProfileIds)" />
135+
CONCAT(sample.stable_id, ':', genetic_profile.stable_id) IN (
136+
#{sampleProfileKeys, typeHandler=org.apache.ibatis.type.ArrayTypeHandler}
137+
)
138+
<bind name="profileArray" value="@org.cbioportal.legacy.persistence.mybatis.util.SqlUtils@listToArray(molecularProfileIds)" />
139+
AND genetic_profile.stable_id IN (
140+
#{profileArray, typeHandler=org.apache.ibatis.type.ArrayTypeHandler}
141+
)
136142
</if>
137143
)
138144
</if>

src/main/resources/org/cbioportal/legacy/persistence/mybatis/NamespaceMapper.xml

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,17 +28,17 @@
2828
</if>
2929
<if test="sampleIds != null">
3030
<if test="@java.util.Arrays@stream(studyIds.toArray()).distinct().count() == 1">
31+
<bind name="sampleArray" value="@org.cbioportal.legacy.persistence.mybatis.util.SqlUtils@listToArray(sampleIds)" />
3132
cancer_study.CANCER_STUDY_IDENTIFIER = #{studyIds[0]} AND
32-
sample.STABLE_ID IN
33-
<foreach item="item" collection="sampleIds" open="(" separator="," close=")">
34-
#{item}
35-
</foreach>
33+
sample.STABLE_ID IN (
34+
#{sampleArray, typeHandler=org.apache.ibatis.type.ArrayTypeHandler}
35+
)
3636
</if>
3737
<if test="@java.util.Arrays@stream(studyIds.toArray()).distinct().count() > 1">
38-
(cancer_study.CANCER_STUDY_IDENTIFIER, sample.STABLE_ID) IN
39-
<foreach index="i" collection="sampleIds" open="(" separator="," close=")">
40-
(#{studyIds[${i}]}, #{sampleIds[${i}]})
41-
</foreach>
38+
<bind name="sampleUniqueKeys" value="@org.cbioportal.legacy.persistence.mybatis.util.SqlUtils@combineStudyAndPatientIds(studyIds, sampleIds)" />
39+
CONCAT(cancer_study.CANCER_STUDY_IDENTIFIER, ':', sample.STABLE_ID) IN (
40+
#{sampleUniqueKeys, typeHandler=org.apache.ibatis.type.ArrayTypeHandler}
41+
)
4242
</if>
4343
</if>
4444
</where>

src/main/resources/org/cbioportal/legacy/persistence/mybatis/SampleMapper.xml

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,17 @@
3737
</if>
3838
<if test="sampleIds != null">
3939
<if test="@java.util.Arrays@stream(studyIds.toArray()).distinct().count() == 1">
40+
<bind name="sampleArray" value="@org.cbioportal.legacy.persistence.mybatis.util.SqlUtils@listToArray(sampleIds)" />
4041
cancer_study.cancer_study_identifier = #{studyIds[0]} AND
41-
sample.stable_id IN
42-
<foreach item="item" collection="sampleIds" open="(" separator="," close=")">#{item}</foreach>
42+
sample.stable_id IN (
43+
#{sampleArray, typeHandler=org.apache.ibatis.type.ArrayTypeHandler}
44+
)
4345
</if>
4446
<if test="@java.util.Arrays@stream(studyIds.toArray()).distinct().count() > 1">
45-
(cancer_study.cancer_study_identifier,sample.stable_id) IN
46-
<foreach index="i" collection="sampleIds" open="(" separator="," close=")">(#{studyIds[${i}]},#{sampleIds[${i}]})</foreach>
47+
<bind name="sampleUniqueKeys" value="@org.cbioportal.legacy.persistence.mybatis.util.SqlUtils@combineStudyAndPatientIds(studyIds, sampleIds)" />
48+
CONCAT(cancer_study.cancer_study_identifier, ':', sample.stable_id) IN (
49+
#{sampleUniqueKeys, typeHandler=org.apache.ibatis.type.ArrayTypeHandler}
50+
)
4751
</if>
4852
</if>
4953
<if test="patientId != null">
@@ -170,13 +174,17 @@
170174
<include refid="from"/>
171175
WHERE
172176
<if test="@java.util.Arrays@stream(studyIds.toArray()).distinct().count() == 1">
177+
<bind name="patientArray" value="@org.cbioportal.legacy.persistence.mybatis.util.SqlUtils@listToArray(patientIds)" />
173178
cancer_study.cancer_study_identifier = #{studyIds[0]} AND
174-
patient.stable_id IN
175-
<foreach item="item" collection="patientIds" open="(" separator="," close=")">#{item}</foreach>
179+
patient.stable_id IN (
180+
#{patientArray, typeHandler=org.apache.ibatis.type.ArrayTypeHandler}
181+
)
176182
</if>
177183
<if test="@java.util.Arrays@stream(studyIds.toArray()).distinct().count() > 1">
178-
(cancer_study.cancer_study_identifier,patient.stable_id) IN
179-
<foreach index="i" collection="patientIds" open="(" separator="," close=")">(#{studyIds[${i}]},#{patientIds[${i}]})</foreach>
184+
<bind name="patientUniqueKeys" value="@org.cbioportal.legacy.persistence.mybatis.util.SqlUtils@combineStudyAndPatientIds(studyIds, patientIds)" />
185+
CONCAT(cancer_study.cancer_study_identifier, ':', patient.stable_id) IN (
186+
#{patientUniqueKeys, typeHandler=org.apache.ibatis.type.ArrayTypeHandler}
187+
)
180188
</if>
181189
</select>
182190
</mapper>

src/main/resources/org/cbioportal/legacy/persistence/mybatis/StructuralVariantMapper.xml

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,13 +61,17 @@
6161
</when>
6262
<otherwise>
6363
<if test="@java.util.Arrays@stream(molecularProfileIds.toArray()).distinct().count() == 1">
64+
<bind name="sampleArray" value="@org.cbioportal.legacy.persistence.mybatis.util.SqlUtils@listToArray(sampleIds)" />
6465
genetic_profile.stable_id = #{molecularProfileIds[0]} AND
65-
sample.stable_id IN
66-
<foreach item="item" collection="sampleIds" open="(" separator="," close=")">#{item}</foreach>
66+
sample.stable_id IN (
67+
#{sampleArray, typeHandler=org.apache.ibatis.type.ArrayTypeHandler}
68+
)
6769
</if>
6870
<if test="@java.util.Arrays@stream(molecularProfileIds.toArray()).distinct().count() > 1">
69-
(sample.stable_id,genetic_profile.stable_id) IN
70-
<foreach index="i" collection="sampleIds" open="(" separator="," close=")">(#{sampleIds[${i}]},#{molecularProfileIds[${i}]})</foreach>
71+
<bind name="sampleProfileKeys" value="@org.cbioportal.legacy.persistence.mybatis.util.SqlUtils@combineStudyAndPatientIds(sampleIds, molecularProfileIds)" />
72+
CONCAT(sample.stable_id, ':', genetic_profile.stable_id) IN (
73+
#{sampleProfileKeys, typeHandler=org.apache.ibatis.type.ArrayTypeHandler}
74+
)
7175
</if>
7276
</otherwise>
7377
</choose>

0 commit comments

Comments
 (0)