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

MySQL索引失效的八大常見場(chǎng)景及解決方法

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

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

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

錯(cuò)誤案例

	-- 對(duì)索引列使用函數(shù)導(dǎo)致全表掃描

	SELECT * FROM orders 

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

執(zhí)行計(jì)劃

	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)換

錯(cuò)誤案例

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

執(zhí)行計(jì)劃

	type: ALL (全表掃描)

	key: NULL (未使用索引)

Java優(yōu)化方案

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

3. OR條件濫用

錯(cuò)誤案例

	-- OR條件導(dǎo)致索引失效
	SELECT * FROM products 
	WHERE category_id = 1 OR price > 1000;  -- 即使category_id有索引也會(huì)失效

執(zhí)行計(jì)劃

	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/!=/<> 操作

錯(cuò)誤案例

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

執(zhí)行計(jì)劃

	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. 復(fù)合索引違反最左前綴

錯(cuò)誤案例

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

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

	-- 查詢未使用最左前綴導(dǎo)致索引失效

	SELECT * FROM orders 

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

執(zhí)行計(jì)劃

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

Java優(yōu)化方案

	// 確保查詢條件包含復(fù)合索引的最左前綴
	@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查詢以通配符開頭

錯(cuò)誤案例

	-- LIKE '%keyword%'導(dǎo)致索引失效
	SELECT * FROM articles 
	WHERE title LIKE '%MySQL%';  -- 即使title有索引也會(huì)失效

執(zhí)行計(jì)劃

	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. 索引列參與計(jì)算

錯(cuò)誤案例

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

執(zhí)行計(jì)劃

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

Java優(yōu)化方案

	// 將計(jì)算邏輯移到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ù)分布不均導(dǎo)致索引失效

錯(cuò)誤案例

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

執(zhí)行計(jì)劃

	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:實(shí)際使用的索引
  • rows:預(yù)估需要檢查的行數(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)化最佳實(shí)踐

3.1 索引設(shè)計(jì)三原則

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

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

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

	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到復(fù)合索引)

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

3.2 Java代碼中的索引保護(hù)

	// 使用@Query注解強(qiáng)制使用索引(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è)查詢優(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í)行計(jì)劃分析:通過EXPLAIN確認(rèn)是否使用了預(yù)期的索引
  • 數(shù)據(jù)類型檢查:確保Java參數(shù)類型與數(shù)據(jù)庫(kù)字段類型匹配
  • SQL改寫測(cè)試:對(duì)可疑SQL進(jìn)行等價(jià)改寫并對(duì)比性能

4.2 常見誤區(qū)

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

4.3 終極建議

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

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

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

相關(guān)文章

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

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

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

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

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

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

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

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

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

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

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

    mysql的約束及實(shí)例分析

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

    MySQL中對(duì)查詢結(jié)果排序和限定結(jié)果的返回?cái)?shù)量的用法教程

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

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

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

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

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

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

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

最新評(píng)論

大冶市| 常德市| 宣汉县| 兴仁县| 封丘县| 米林县| 卢氏县| 河池市| 美姑县| 龙里县| 四会市| 肇庆市| 丹江口市| 西吉县| 巴林左旗| 额尔古纳市| 恩施市| 大渡口区| 东方市| 大悟县| 涿州市| 集安市| 库车县| 达孜县| 武汉市| 大丰市| 中卫市| 洛阳市| 昌平区| 綦江县| 兴化市| 马龙县| 长泰县| 陇南市| 郴州市| 凉城县| 会理县| 临江市| 遂平县| 湟源县| 兴仁县|