亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

MySQL索引失效的八大常見場景及解決方法

 更新時間:2025年05月09日 08:57:26   作者:Java小陸  
作為一名Java開發(fā)工程師,在處理高并發(fā)業(yè)務時,MySQL索引失效是導致系統(tǒng)性能下降的"隱形殺手",本文將結(jié)合實際案例,深度剖析索引失效的8大常見場景,并提供Java代碼層面的優(yōu)化建議,幫助開發(fā)者避開性能陷阱,需要的朋友可以參考下

一、索引失效的"元兇"TOP 8

1. 函數(shù)操作導致索引失效

錯誤案例

	-- 對索引列使用函數(shù)導致全表掃描

	SELECT * FROM orders 

	WHERE DATE(create_time) = '2023-01-01';  -- 即使create_time有索引也會失效

執(zhí)行計劃

	type: ALL (全表掃描)

	key: NULL (未使用索引)

Java優(yōu)化方案

	// 使用范圍查詢替代函數(shù)操作
	@Query("SELECT o FROM Order o WHERE o.createTime >= :startDate AND o.createTime < :endDate")

	List<Order> findByDateRange(@Param("startDate") LocalDateTime start, 

	                          @Param("endDate") LocalDateTime end);

2. 隱式類型轉(zhuǎn)換

錯誤案例

	-- 字符串與數(shù)字比較導致索引失效
	SELECT * FROM users 
	WHERE phone = 13800138000;  -- phone是VARCHAR類型

執(zhí)行計劃

	type: ALL (全表掃描)

	key: NULL (未使用索引)

Java優(yōu)化方案

	// 確保參數(shù)類型與數(shù)據(jù)庫字段類型一致
	@Query("SELECT u FROM User u WHERE u.phone = :phone")
	User findByPhone(@Param("phone") String phone);  // 使用String而非Long

3. OR條件濫用

錯誤案例

	-- OR條件導致索引失效
	SELECT * FROM products 
	WHERE category_id = 1 OR price > 1000;  -- 即使category_id有索引也會失效

執(zhí)行計劃

	type: ALL (全表掃描)
	key: NULL (未使用索引)

Java優(yōu)化方案

	// 使用UNION ALL替代OR條件
	@Query("SELECT p FROM Product p WHERE p.categoryId = :categoryId " +
	       "UNION ALL " +
	       "SELECT p FROM Product p WHERE p.price > :price AND p.categoryId != :categoryId")

	List<Product> findByCategoryOrPrice(@Param("categoryId") Long categoryId, 

	                                   @Param("price") BigDecimal price);

4. NOT IN/!=/<> 操作

錯誤案例

	-- NOT IN導致索引失效
	SELECT * FROM orders 
	WHERE status NOT IN (1, 2, 3);  -- 即使status有索引也會失效

執(zhí)行計劃

	type: ALL (全表掃描)
	key: NULL (未使用索引)

Java優(yōu)化方案

	// 使用LEFT JOIN + IS NULL替代NOT IN
	@Query("SELECT o FROM Order o " +
	       "LEFT JOIN OrderStatus os ON o.status = os.id AND os.id IN (1,2,3) " +
	       "WHERE os.id IS NULL")
	List<Order> findByStatusNotIn(@Param("statusList") List<Integer> statusList);

5. 復合索引違反最左前綴

錯誤案例

	-- 創(chuàng)建復合索引 (user_id, status, create_time)

	ALTER TABLE orders ADD INDEX idx_user_status_time (user_id, status, create_time);

	-- 查詢未使用最左前綴導致索引失效

	SELECT * FROM orders 

	WHERE status = 1 AND create_time > '2023-01-01';  -- 缺少user_id條件

執(zhí)行計劃

	type: ALL (全表掃描)
	key: NULL (未使用索引)

Java優(yōu)化方案

	// 確保查詢條件包含復合索引的最左前綴
	@Query("SELECT o FROM Order o WHERE o.userId = :userId AND o.status = :status " +
	       "AND o.createTime > :startTime")
	List<Order> findByUserStatusAndTime(@Param("userId") Long userId, 
	                                  @Param("status") Integer status,
	                                  @Param("startTime") LocalDateTime startTime);

6. LIKE查詢以通配符開頭

錯誤案例

	-- LIKE '%keyword%'導致索引失效
	SELECT * FROM articles 
	WHERE title LIKE '%MySQL%';  -- 即使title有索引也會失效

執(zhí)行計劃

	type: ALL (全表掃描)
	key: NULL (未使用索引)

Java優(yōu)化方案

	// 使用全文索引替代LIKE模糊查詢
	@Entity
	@Table(indexes = {
	    @Index(name = "idx_title_fulltext", columnList = "title", 
	           type = IndexType.FULLTEXT)  // MySQL 5.6+支持

	})
	public class Article {

	    // ...

	}

	 

	// 查詢示例
	@Query(value = "SELECT a FROM Article a WHERE MATCH(a.title) AGAINST(:keyword IN BOOLEAN MODE)",

	       nativeQuery = true)

	List<Article> searchByKeyword(@Param("keyword") String keyword);

7. 索引列參與計算

錯誤案例

	-- 索引列參與計算導致失效
	SELECT * FROM users 
	WHERE YEAR(birthday) = 1990;  -- 即使birthday有索引也會失效

執(zhí)行計劃

	type: ALL (全表掃描)
	key: NULL (未使用索引)

Java優(yōu)化方案

	// 將計算邏輯移到Java端或使用范圍查詢
	@Query("SELECT u FROM User u WHERE u.birthday >= :start AND u.birthday < :end")
	List<User> findByBirthYear(@Param("start") LocalDate start, 
	                          @Param("end") LocalDate end);

	// 調(diào)用示例

	LocalDate start = LocalDate.of(1990, 1, 1);

	LocalDate end = LocalDate.of(1991, 1, 1);

	List<User> users = userRepository.findByBirthYear(start, end);

8. 數(shù)據(jù)分布不均導致索引失效

錯誤案例

	-- 性別字段(區(qū)分度極低)即使有索引也會失效
	SELECT * FROM users 
	WHERE gender = 'M';  -- 假設男女比例接近1:1

執(zhí)行計劃

	type: ALL (全表掃描)
	key: NULL (優(yōu)化器選擇全表掃描)

Java優(yōu)化方案

	// 避免為低區(qū)分度字段建索引

	// 或改用其他高區(qū)分度條件

	@Query("SELECT u FROM User u WHERE u.gender = :gender AND u.status = :status")

	List<User> findByGenderAndStatus(@Param("gender") String gender, 

	                                @Param("status") Integer status);

二、索引失效的"診斷工具箱"

2.1 EXPLAIN命令深度解析

	EXPLAIN SELECT * FROM orders WHERE user_id = 12345;

關鍵字段說明

  • type:訪問類型(ALL=全表掃描,index=索引掃描,range=范圍掃描,ref=索引引用)
  • key:實際使用的索引
  • rows:預估需要檢查的行數(shù)
  • Extra:額外信息(Using index=覆蓋索引,Using where=需回表)

2.2 Java中的慢查詢監(jiān)控

	// Spring Boot配置示例(application.properties)
	spring.datasource.hikari.connection-test-query=SELECT 1
	spring.jpa.properties.hibernate.generate_statistics=true
	spring.jpa.properties.hibernate.session.events.log.LOG_QUERIES_SLOWER_THAN_MS=100

	// 自定義攔截器記錄慢查詢

	@Component
	public class SlowQueryInterceptor implements HandlerInterceptor {
	    @Override

	    public boolean preHandle(HttpServletRequest request, 

	                             HttpServletResponse response, 

	                             Object handler) {

	        long startTime = System.currentTimeMillis();

	        request.setAttribute("startTime", startTime);

	        return true;

	    }

	    @Override

	    public void afterCompletion(HttpServletRequest request, 

	                                HttpServletResponse response, 

	                                Object handler, 

	                                Exception ex) {

	        long startTime = (Long) request.getAttribute("startTime");

	        long duration = System.currentTimeMillis() - startTime;

	        if (duration > 500) {  // 記錄超過500ms的查詢

	            logger.warn("Slow query detected: {}ms, URL: {}", 

	                       duration, request.getRequestURI());

	        }

	    }

	}

三、索引優(yōu)化最佳實踐

3.1 索引設計三原則

  • 選擇性原則:優(yōu)先為區(qū)分度高的列建索引(如用戶ID、訂單號)

  • 復合索引順序:高頻查詢條件放前面,范圍查詢條件放最后

	-- 正確示例:先等值查詢,后范圍查詢

	ALTER TABLE orders ADD INDEX idx_user_status_time (user_id, status, create_time);
  • 覆蓋索引優(yōu)化:讓查詢完全通過索引獲取數(shù)據(jù)
	-- 優(yōu)化前

	SELECT user_id, order_no FROM orders WHERE user_id = 12345;

	-- 優(yōu)化后(添加order_no到復合索引)

	ALTER TABLE orders ADD INDEX idx_user_order (user_id, order_no);

3.2 Java代碼中的索引保護

	// 使用@Query注解強制使用索引(MySQL 5.7+)

	@Query(value = "SELECT * FROM orders FORCE INDEX(idx_user_status_time) " +

	       "WHERE user_id = :userId AND status = :status",

	       nativeQuery = true)

	List<Order> findByUserIdAndStatus(@Param("userId") Long userId, 

	                                 @Param("status") Integer status);

	 

	// 分頁查詢優(yōu)化(避免大偏移量)

	public interface OrderRepository extends JpaRepository<Order, Long> {

	    @Query("SELECT o FROM Order o WHERE o.userId = :userId " +

	           "AND (o.createTime < :lastCreateTime OR " +

	           "(o.createTime = :lastCreateTime AND o.id < :lastId)) " +

	           "ORDER BY o.createTime DESC, o.id DESC")

	    List<Order> findAfterCursor(@Param("userId") Long userId,

	                              @Param("lastCreateTime") Date lastCreateTime,

	                              @Param("lastId") Long lastId,

	                              Pageable pageable);

	}

四、總結(jié)與避坑指南

4.1 索引失效"三板斧"診斷法

  • 執(zhí)行計劃分析:通過EXPLAIN確認是否使用了預期的索引
  • 數(shù)據(jù)類型檢查:確保Java參數(shù)類型與數(shù)據(jù)庫字段類型匹配
  • SQL改寫測試:對可疑SQL進行等價改寫并對比性能

4.2 常見誤區(qū)

  • 索引越多越好(導致寫入性能下降)
  • 為所有查詢條件建索引(浪費存儲空間)
  • 依賴ORM框架自動生成SQL(可能生成低效SQL)

4.3 終極建議

"先診斷,后優(yōu)化"原則:通過慢查詢?nèi)罩?、EXPLAIN和性能監(jiān)控工具定位問題,再結(jié)合業(yè)務場景選擇最優(yōu)的索引方案。

通過本文的系統(tǒng)性講解,Java開發(fā)者可以掌握MySQL索引失效的核心原因和解決方案。在實際項目中,建議結(jié)合A/B測試驗證優(yōu)化效果,讓系統(tǒng)性能再上新臺階!

以上就是MySQL索引失效的八大常見場景及解決方法的詳細內(nèi)容,更多關于MySQL索引失效場景的資料請關注腳本之家其它相關文章!

相關文章

  • MySQL查詢in操作 查詢結(jié)果按in集合順序顯示

    MySQL查詢in操作 查詢結(jié)果按in集合順序顯示

    MySQL 查詢in操作,查詢結(jié)果按in集合順序顯示的實現(xiàn)代碼,需要的朋友可以參考下。
    2010-12-12
  • MySQL事務的基礎學習以及心得分享

    MySQL事務的基礎學習以及心得分享

    本篇內(nèi)容是關于MySQL事務的基礎知識學習內(nèi)容,并把學習中網(wǎng)友的心得做了總結(jié),分享給大家,一起學習參考下吧。
    2017-12-12
  • MYSQL行列轉(zhuǎn)置方式

    MYSQL行列轉(zhuǎn)置方式

    本文介紹了如何使用MySQL和Navicat進行列轉(zhuǎn)行操作,首先,創(chuàng)建了一個名為`grade`的表,并插入多條數(shù)據(jù),然后,通過修改查詢SQL語句,使用`CASE`和`IF`函數(shù)將列轉(zhuǎn)換為行,總結(jié)指出,`SUM`可以替換為`MAX`、`MIN`、`AVG`等聚合函數(shù),并且在查詢中需要對普通字段進行分組
    2025-01-01
  • mysql開啟遠程連接(mysql開啟遠程訪問)

    mysql開啟遠程連接(mysql開啟遠程訪問)

    開啟MYSQL遠程連接權(quán)限的方法,大家參考使用吧
    2013-12-12
  • MySQL誤刪后使用binlog恢復數(shù)據(jù)的實現(xiàn)方法

    MySQL誤刪后使用binlog恢復數(shù)據(jù)的實現(xiàn)方法

    這篇文章主要介紹了MySQL誤刪后使用binlog恢復數(shù)據(jù)的實現(xiàn)方法,使用 binlog 恢復數(shù)據(jù)的預期效果是將誤刪的數(shù)據(jù)還原到誤刪之前的狀態(tài),以減少或消除數(shù)據(jù)丟失的影響,文中有相關的代碼示例和圖文介紹,需要的朋友可以參考下
    2024-05-05
  • 5個保護MySQL數(shù)據(jù)倉庫的小技巧

    5個保護MySQL數(shù)據(jù)倉庫的小技巧

    這篇文章主要為大家詳細介紹了五個小技巧,告訴你如何保護MySQL數(shù)據(jù)倉庫,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-08-08
  • MySQL執(zhí)行SQL文件報錯:Unknown collation ‘utf8mb4_0900_ai_ci‘的解決方案

    MySQL執(zhí)行SQL文件報錯:Unknown collation ‘utf8mb4_0900_ai_

    這篇文章主要給大家分享了MySQL執(zhí)行SQL文件出現(xiàn)【Unknown collation ‘utf8mb4_0900_ai_ci‘】的解決方案,如果又遇到相同問題的同學,可以參考閱讀本文
    2023-09-09
  • MySQL實戰(zhàn)之Insert語句的使用心得

    MySQL實戰(zhàn)之Insert語句的使用心得

    這篇文章主要給大家介紹了關于MySQL實戰(zhàn)之Insert語句的使用心得的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-10-10
  • MySQL如何查看數(shù)據(jù)庫連接數(shù)

    MySQL如何查看數(shù)據(jù)庫連接數(shù)

    本文介紹了在MySQL中查看數(shù)據(jù)庫連接數(shù)的多種方法,包括使用SHOWSTATUS命令、查詢information_schema數(shù)據(jù)庫、使用SHOWPROCESSLIST命令、查看最大連接數(shù)以及使用性能模式,每個方法都有詳細的示例和注意事項,幫助你有效地監(jiān)控和管理數(shù)據(jù)庫連接
    2024-11-11
  • mysql使用insert into select插入查出的數(shù)據(jù)

    mysql使用insert into select插入查出的數(shù)據(jù)

    這篇文章主要介紹了mysql使用insert into select插入查出的數(shù)據(jù)方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-12-12

最新評論