目標
最近,在項目中使用MyBatis進行SQL腳本編寫時,我遇到了以“WHERE 1=1”開頭的WHERE子句的做法,以簡化多個條件的串聯。這里有一個例子來討論這種技術以及“WHERE 1=1”是否對性能有任何影響。
<select id="" parameterType="">SELECT * FROM users WHERE 1=1<if test="userName != null">AND user_name = #{userName}</if><if test="userAge != null">AND user_age = #{userAge}</if><if test="userSex != null">AND user_sex = #{userSex}</if>
</select>
討論MyBatis中連接條件的兩種常見做法
1、第一種where
<select id="" parameterType="">SELECT * FROM users WHERE 1=1<if test="userName != null">AND user_name = #{userName}</if><if test="userAge != null">AND user_age = #{userAge}</if><if test="userSex != null">AND user_sex = #{userSex}</if>
</select>
2、第二種
MyBatis 提供了一個 標記,僅當至少有一個條件計算結果為 true 時,該標記才會插入 WHERE 子句。如果 AND 或 OR 之前沒有有效的語句,則 元素將刪除它們。
<select id="" parameterType="">SELECT * FROM users <where><if test="userName != null">AND user_name = #{userName}</if><if test="userAge != null">AND user_age = #{userAge}</if><if test="userSex != null">AND user_sex = #{userSex}</if></where>
</select>
性能影響
使用“WHERE 1=1”和 標簽的性能差異在于前者對SQL查詢性能的優化,而后者則在于動態生成SQL語句。我們來詳細分析一下:
1、mysql版本
SELECT VERSION(); -- 5.7.44
插入數據:
CREATE TABLE IF NOT EXISTS users
(id INT NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT 'Auto-increment ID',name VARCHAR(20) COMMENT 'Name',age TINYINT COMMENT 'Age'
) ENGINE = INNODB;INSERT INTO users (name, age) VALUES ('John', 18), ('Jane', 19), ('Doe', 20), ('Smith', 21);
在5.7以上版本中,SQL查詢優化將消除“1=1”部分,不影響索引。不過值得注意的是,較低版本可能會受到一些影響,值得關注。
EXPLAIN SELECT * FROM users WHERE 1=1 AND name = 'John';
SHOW WARNINGS;
優化后的 SQL 表明“1=1”部分已被查詢優化器優化掉,因此不會顯著影響整體性能。
性能比較
– With “WHERE 1=1” AND a condition
SELECT * FROM users WHERE 1=1 AND name = ‘John’;
– Execution Time: 0.046s
– With just “WHERE 1=1”
SELECT * FROM users WHERE 1=1;
– Execution Time: 0.046s
與由 MySQL 服務器的查詢優化器處理的“WHERE 1=1”相比, 標簽處理動態 SQL 構造。然而,它不會顯著影響性能,因為底層動態 SQL 生成并不太復雜。
結論
where 1=1 和 標記都是連接條件的常見做法,對性能沒有重大影響。他們之間的選擇可以基于團隊標準。此外,這些方法的性能不受處理的數據量的影響,因為每次執行僅處理一次,因此即使對于大型數據集,也不存在性能差異。