最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

 更新時間:2025年05月09日 08:57:26   作者:Java小陸  
作為一名Java開發(fā)工程師,在處理高并發(fā)業(yè)務(wù)時,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';  -- 假設(shè)男女比例接近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;

關(guān)鍵字段說明

  • 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 索引設(shè)計三原則

  • 選擇性原則:優(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)罩尽XPLAIN和性能監(jiān)控工具定位問題,再結(jié)合業(yè)務(wù)場景選擇最優(yōu)的索引方案。

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

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

相關(guān)文章

  • mysql 詳解隔離級別操作過程(cmd)

    mysql 詳解隔離級別操作過程(cmd)

    這篇文章主要介紹了mysql 詳解隔離級別操作過程(cmd)的相關(guān)資料,需要的朋友可以參考下
    2017-01-01
  • MySQL字符串轉(zhuǎn)數(shù)值的方法全解析

    MySQL字符串轉(zhuǎn)數(shù)值的方法全解析

    在MySQL開發(fā)中,字符串與數(shù)值的轉(zhuǎn)換是高頻操作,本文從隱式轉(zhuǎn)換原理、顯式轉(zhuǎn)換方法、典型場景案例、風險防控四個維度系統(tǒng)梳理,助您精準掌握這一核心技能,需要的朋友可以參考下
    2025-12-12
  • 詳解mysql持久化統(tǒng)計信息

    詳解mysql持久化統(tǒng)計信息

    這篇文章主要介紹了mysql持久化統(tǒng)計信息的相關(guān)資料,幫助大家更好的理解和使用MySQL數(shù)據(jù)庫,感興趣的朋友可以了解下
    2020-12-12
  • mysql 行列轉(zhuǎn)換的示例代碼

    mysql 行列轉(zhuǎn)換的示例代碼

    這篇文章主要介紹了mysql 行列轉(zhuǎn)換的示例代碼,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-03-03
  • 淺談一下mysql數(shù)據(jù)庫底層原理

    淺談一下mysql數(shù)據(jù)庫底層原理

    這篇文章主要介紹了淺談一下mysql數(shù)據(jù)庫底層原理,介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-04-04
  • mysql的約束及實例分析

    mysql的約束及實例分析

    這篇文章主要介紹了mysql的約束及實例分析,真正約束字段的是數(shù)據(jù)類型,但是數(shù)據(jù)類型約束很單一,需要有一些額外的約束,更好的保證數(shù)據(jù)的合法性,從業(yè)務(wù)邏輯角度保證數(shù)據(jù)的正確性,需要的朋友可以參考下
    2023-07-07
  • MySQL中對查詢結(jié)果排序和限定結(jié)果的返回數(shù)量的用法教程

    MySQL中對查詢結(jié)果排序和限定結(jié)果的返回數(shù)量的用法教程

    這篇文章主要介紹了MySQL中對查詢結(jié)果排序和限定結(jié)果的返回數(shù)量的用法教程,分別講解了Order By語句和Limit語句的基本使用方法,需要的朋友可以參考下
    2015-12-12
  • 你知道m(xù)ysql中空值和null值的區(qū)別嗎

    你知道m(xù)ysql中空值和null值的區(qū)別嗎

    這篇文章主要給大家介紹了關(guān)于mysql中空值和null值區(qū)別的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-01-01
  • Mysql案例刨析事務(wù)隔離級別

    Mysql案例刨析事務(wù)隔離級別

    隔離性其實比想象要復雜。在SQL中定義了四種隔離的級別,每一種隔離級別都規(guī)定了一個事務(wù)中的修改,哪些是在事務(wù)內(nèi)和事務(wù)間是可見的,哪些是不可見的。較低級別的隔離通常來說能承受更高的并發(fā),系統(tǒng)的開銷也會更小
    2021-09-09
  • Mysql查詢表字段結(jié)構(gòu)注釋的方式

    Mysql查詢表字段結(jié)構(gòu)注釋的方式

    這篇文章主要介紹了Mysql查詢表字段結(jié)構(gòu)注釋的方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-08-08

最新評論

建瓯市| 镇雄县| 织金县| 曲阜市| 开原市| 诏安县| 百色市| 东宁县| 荥阳市| 永昌县| 蒙城县| 连云港市| 额济纳旗| 衡南县| 庐江县| 景谷| 武功县| 东乡县| 绥阳县| 蓝田县| 白水县| 遂溪县| 山东省| 尖扎县| 平潭县| 乡宁县| 渑池县| 探索| 康保县| 东乌| 新民市| 鄱阳县| 武威市| 容城县| 五家渠市| 襄城县| 闽侯县| 呼和浩特市| 黑河市| 闽侯县| 乳源|