日誌顯示生成 SQL 含幾十個 OR id = ? 條件:
SELECT * FROM hd_memory_address where id = ? OR id = ? OR id = ? ... (重複 60+ 次)
導致 SQL 解析緩慢、超過數據庫最大 SQL 長度限制、參數綁定錯誤。
where id = #{id} 但傳入 List<Integer>,MyBatis 將列表展開為多個 OR 條件parameterType="int" 與實際傳入 List 不匹配,導致類型轉換異常<foreach> 標籤正確構建 IN 子句<select id="selectByIds" resultType="MemoryAddress">
SELECT * FROM hd_memory_address
<where>
id IN
<foreach collection="list" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</where>
</select>
List<MemoryAddress> selectByIds(@Param("list") List<Integer> ids);
SELECT * FROM hd_memory_address WHERE id IN (?, ?, ?, ...) -- 單個 IN 子句,參數扁平化
單次 IN 參數建議 不超過 1000 個(Oracle 限制 1000,MySQL/PostgreSQL 無硬性限制但性能下降)。大量 ID 分批處理:
public List<MemoryAddress> selectByIdsBatch(List<Integer> ids) {
List<MemoryAddress> result = new ArrayList<>();
for (int i = 0; i < ids.size(); i += 1000) {
List<Integer> batch = ids.subList(i, Math.min(i + 1000, ids.size()));
result.addAll(mapper.selectByIds(batch));
}
return result;
}
超大批次(萬級以上)建議:
CREATE TEMPORARY TABLE tmp_ids (id INT PRIMARY KEY) 批量插入 ID,再 JOIN 查詢Table-Valued Parameter 傳遞 ID 表unnest(ARRAY[...]) 配合 ANY原問題中 parameterType="int" 應改為 java.util.List 或移除(MyBatis 自動推斷)。#{id} vs #id#:前者預編譯參數化(防注入),後者字符串替換(極度不推薦)。
logging.level.org.apache.ibatis=DEBUG 查看實際 SQL 與參數Explain 分析 IN 子句執行計劃,確認索引命中IN vs JOIN 臨時表 在實際數據量下的性能