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

記一次mysql線上分頁排序亂序問題解決

 更新時間:2026年03月05日 10:08:47   作者:姜文憲  
本文主要介紹了mysql線上分頁排序亂序問題解決,由于在分頁查詢時未正確使用ORDERBY和LIMIT導(dǎo)致的跨頁數(shù)據(jù)重復(fù)問題,下面就來詳細(xì)的介紹一下解決方法,感興趣的可以了解一下

1. 觸發(fā)版本

MySQL 8.0

2. 問題描述

優(yōu)化列表分頁查詢接口時,將默認(rèn)的無排序條件查詢修改為按照時間(create_at)條件排序,由于 order by 與 limit 混用時未加唯一限定排序條件,導(dǎo)致分頁結(jié)果中出現(xiàn)了跨頁重復(fù)的數(shù)據(jù)。

3. 問題復(fù)現(xiàn)

3.1 復(fù)現(xiàn)數(shù)據(jù)腳本

-- 1. 創(chuàng)建測試表
DROP TABLE IF EXISTS test_pagination;
CREATE TABLE test_pagination (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    status VARCHAR(20),
    created_at DATETIME,
    updated_at DATETIME
);

-- 2. 創(chuàng)建存儲過程
DELIMITER $$

DROP PROCEDURE IF EXISTS generate_pagination_test_data$$
CREATE PROCEDURE generate_pagination_test_data(
    IN total_rows INT,          -- 總記錄數(shù)
    IN batch_size INT,          -- 批次大?。ㄏ嗤瑫r間的記錄數(shù))
    IN start_date VARCHAR(19),  -- 開始時間
    IN end_date VARCHAR(19)     -- 結(jié)束時間
)
BEGIN
    DECLARE i INT DEFAULT 0;
    DECLARE batch_count INT DEFAULT 0;
    DECLARE batch_time DATETIME;
    DECLARE start_time DATETIME;
    DECLARE end_time DATETIME;
    DECLARE total_seconds INT;
    DECLARE interval_seconds INT;
    DECLARE total_batches INT;
    DECLARE current_batch INT DEFAULT 0;

    -- 所有變量聲明
    SET start_time = STR_TO_DATE(start_date, '%Y-%m-%d %H:%i:%s');
    SET end_time = STR_TO_DATE(end_date, '%Y-%m-%d %H:%i:%s');
    SET total_seconds = TIMESTAMPDIFF(SECOND, start_time, end_time);

    -- 計算總批次數(shù)和批次時間間隔
    SET total_batches = CEIL(total_rows / batch_size);
    SET interval_seconds = FLOOR(total_seconds / total_batches);
    IF interval_seconds < 1 THEN SET interval_seconds = 1; END IF;

    -- 設(shè)置初始批次時間
    SET batch_time = start_time;
    SET current_batch = 0;

    -- 性能優(yōu)化設(shè)置
    SET autocommit = 0;
    SET unique_checks = 0;
    SET foreign_key_checks = 0;

    -- 開始生成數(shù)據(jù)
    WHILE i < total_rows DO
        -- 如果批次計數(shù)器為0,表示開始新批次
        IF batch_count = 0 THEN
            -- 為這個批次生成一個時間
            SET batch_time = DATE_ADD(start_time,
                INTERVAL current_batch * interval_seconds +
                FLOOR(RAND() * 60) SECOND  -- 加一些隨機(jī)偏移
            );
            SET current_batch = current_batch + 1;
        END IF;

        -- 插入記錄(同批次記錄時間相同)
        INSERT INTO test_pagination (status, created_at, updated_at)
        VALUES (
            CASE
                WHEN RAND() < 0.6 THEN 'active'
                WHEN RAND() < 0.9 THEN 'pending'
                ELSE 'deleted'
            END,
            batch_time,
            batch_time
        );

        -- 更新計數(shù)器
        SET i = i + 1;
        SET batch_count = batch_count + 1;

        -- 如果達(dá)到批次大小,重置批次計數(shù)器
        IF batch_count >= batch_size THEN
            SET batch_count = 0;
        END IF;

        -- 每5000條提交一次
        IF i % 5000 = 0 THEN
            COMMIT;
        END IF;
    END WHILE;

    -- 最終提交
    COMMIT;

    -- 恢復(fù)設(shè)置
    SET autocommit = 1;
    SET unique_checks = 1;
    SET foreign_key_checks = 1;

END$$

DELIMITER ;

-- 3. 調(diào)用存儲過程生成數(shù)據(jù)
-- 生成1萬條數(shù)據(jù),每批次7條相同時間,時間從2026-01-01到2026-01-01
CALL generate_pagination_test_data(
    10000,      -- 總記錄數(shù)
    7,          -- 批次大?。ㄏ嗤瑫r間的記錄數(shù))
    '2026-01-01 00:00:00',
    '2026-01-01 23:59:59'
);

-- 4. 清理存儲過程
DROP PROCEDURE IF EXISTS generate_pagination_test_data;

3.2 復(fù)現(xiàn)條件

  1. 執(zhí)行分頁查詢 (第3頁, 每頁10條)

    select * from test_pagination order by created_at limit 20, 10
    

  1. 執(zhí)行分頁查詢(第4頁, 每頁10條)

    select * from test_pagination order by created_at limit 30, 10
    

    ?

結(jié)果中 ID 為 31 的數(shù)據(jù)再次出現(xiàn),存在跨頁數(shù)據(jù)重復(fù)問題。

4. 問題分析

4.1 問題溯源

與前端聯(lián)調(diào)時發(fā)現(xiàn)分頁數(shù)據(jù)重復(fù)、主鍵 ID 順序不穩(wěn)定,與未加排序條件前的結(jié)果不一致,定位到核心問題為ORDER BY + LIMIT的使用方式不正確所導(dǎo)致。

4.2 核心原理

MySQL 5.6+ 對 ORDER BY ... LIMIT n 場景做了優(yōu)化

  • 若排序無法利用索引有序特性,會啟用優(yōu)先隊列(Priority Queue) 進(jìn)行排序優(yōu)化。不再對全量數(shù)據(jù)排序,而是維護(hù)一個大小為limit n的堆結(jié)構(gòu),遍歷數(shù)據(jù)時僅將符合條件的數(shù)據(jù)插入堆中,遍歷完成后直接取堆內(nèi)數(shù)據(jù)返回。
  • 當(dāng)排序字段(created_at)存在重復(fù)值時,MySQL 無法保證相同時間的記錄選取順序固定,對相同時間的記錄隨機(jī)保留最終導(dǎo)致分頁結(jié)果亂序、重復(fù)。

4.3 歷史邏輯分析

迭代前未顯式指定ORDER BY條件時,MySQL 會按聚簇索引的物理存儲順序進(jìn)行隱式排序(看似無重復(fù)),實際開發(fā)過程中中不應(yīng)該依賴該特性,所有排序查詢都需要顯式指定ORDER BY條件。

4.4 文檔資料

來源:MySQL 8.0 官方文檔 - ORDER BY 優(yōu)化

核心內(nèi)容:

If you combine LIMIT *row_count* with ORDER BY, MySQL stops sorting as soon as it has found the first row_count rows of the sorted result, rather than sorting the entire result. If ordering is done by using an index, this is very fast. If a filesort must be done, all rows that match the query without the LIMIT clause are selected, and most or all of them are sorted, before the first row_count are found. After the initial rows have been found, MySQL does not sort any remainder of the result set.

One manifestation of this behavior is that an ORDER BY query with and without LIMIT may return rows in different order, as described later in this section.

5. 解決方案

ORDER BY的排序條件末尾補(bǔ)充具有唯一性的排序字段(主鍵 ID、唯一索引等),確保相同排序字段值的記錄排序順序固定,徹底解決分頁重復(fù)問題。

5.1 優(yōu)化后的式例

-- 優(yōu)化前
SELECT * FROM test_pagination ORDER BY created_at LIMIT 20, 10;

-- 優(yōu)化后
SELECT * FROM test_pagination ORDER BY created_at, id LIMIT 20, 10;

5.2 優(yōu)化原則

使用排序字段 + 唯一特性字段組合排

  • 使用created_at字段排序滿足業(yè)務(wù)側(cè)按時間展示需要。
  • 時間相同的記錄按照主鍵值進(jìn)行二次排序,避免分頁亂序。

6. 避坑指南

  1. 所有分頁查詢的ORDER BY條件必須包含唯一字段(主鍵 / 唯一索引),避免分頁亂序;
  2. 避免依賴 MySQL 隱式排序特性(無ORDER BY時按照物理存儲順序排序),顯式指定排序條件;

到此這篇關(guān)于記一次mysql線上分頁排序亂序問題解決的文章就介紹到這了,更多相關(guān)mysql線上分頁排序亂序內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • CentOS 7 安裝Percona Server+Mysql

    CentOS 7 安裝Percona Server+Mysql

    這篇文章主要介紹了CentOS 7 安裝Percona Server+Mysql的相關(guān)資料,需要的朋友可以參考下
    2018-11-11
  • MySQL中關(guān)于表的約束

    MySQL中關(guān)于表的約束

    在MySQL中,約束用于定義表的規(guī)則和限制,確保數(shù)據(jù)的準(zhǔn)確性和可靠性,主要類型包括NOT NULL、DEFAULT、PRIMARY KEY、AUTO_INCREMENT、UNIQUE KEY、FOREIGN KEY、CHECK和INDEX等,NOT NULL約束確保列不能存儲NULL值;DEFAULT設(shè)置默認(rèn)值
    2024-09-09
  • MySQL 語句執(zhí)行順序舉例解析

    MySQL 語句執(zhí)行順序舉例解析

    這篇文章主要介紹了MySQL 語句執(zhí)行順序舉例解析,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價值需要的小伙伴可以參考一下
    2022-06-06
  • MySQL中的時區(qū)設(shè)置方式

    MySQL中的時區(qū)設(shè)置方式

    這篇文章主要介紹了MySQL中的時區(qū)設(shè)置方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-11-11
  • 利用SQL批量修改Nacos配置的操作代碼

    利用SQL批量修改Nacos配置的操作代碼

    在Nacos的應(yīng)用場景中,配置信息的管理至關(guān)重要,當(dāng)需要對特定的配置進(jìn)行批量修改時,SQL能成為我們強(qiáng)大的助力工具,本文將圍繞如何使用SQL語句,依據(jù)特定條件修改Nacos的config_info表配置展開講解,需要的朋友可以參考下
    2025-05-05
  • MySQL可重復(fù)讀級別能夠解決幻讀嗎

    MySQL可重復(fù)讀級別能夠解決幻讀嗎

    這篇文章主要給大家介紹了關(guān)于MySQL可重復(fù)讀級別能否解決幻讀的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用MySQL具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-03-03
  • MySQL數(shù)據(jù)庫服務(wù)多實例部署完整指南

    MySQL數(shù)據(jù)庫服務(wù)多實例部署完整指南

    MySQL多實例部署指的是在同一臺服務(wù)器上同時運(yùn)行多個獨(dú)立的MySQL實例,每個實例有自己的配置、數(shù)據(jù)目錄和端口,這篇文章主要介紹了MySQL數(shù)據(jù)庫服務(wù)多實例部署的相關(guān)資料,需要的朋友可以參考下
    2026-04-04
  • CentOS7環(huán)境下MySQL8常用命令小結(jié)

    CentOS7環(huán)境下MySQL8常用命令小結(jié)

    在進(jìn)行MySQL的優(yōu)化之前必須要了解的就是MySQL的查詢過程,下面這篇文章主要給大家介紹了關(guān)于CentOS7環(huán)境下MySQL8常用命令的相關(guān)資料,文中通過實例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-06-06
  • mysql 8.0.29 卸載問題小結(jié)

    mysql 8.0.29 卸載問題小結(jié)

    近我將筆記本重裝了,為了保留之前的程序,我把相關(guān)的注冊表和環(huán)境備份了下來,重裝之后重新導(dǎo)入成功再現(xiàn)了部分軟件,下面給大家分享mysql 8.0.29 卸載問題記錄,感興趣的朋友一起看看吧
    2024-04-04
  • MYSQL慢查詢與日志的設(shè)置與測試

    MYSQL慢查詢與日志的設(shè)置與測試

    這篇文章主要給大家介紹了關(guān)于MYSQL慢查詢與日志的設(shè)置與測試,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-01-01

最新評論

海晏县| 普陀区| 沂水县| 洛阳市| 洪洞县| 南江县| 门源| 德安县| 蒲城县| 镇赉县| 泰安市| 高州市| 长武县| 会东县| 蓬安县| 大竹县| 揭阳市| 平谷区| 手游| 二连浩特市| 苏尼特右旗| 凌云县| 长沙市| 永丰县| 临漳县| 丹东市| 郑州市| 神池县| 荃湾区| 阿坝县| 平泉县| 道孚县| 金堂县| 舒城县| 吴桥县| 滕州市| 呼图壁县| 宜城市| 涞源县| 田阳县| 东莞市|