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

MySQL透明頁壓縮(TPC)批量取消與磁盤碎片優(yōu)化實戰(zhàn)案例

 更新時間:2026年07月22日 09:19:42   作者:Seal^_^  
這篇文章主要介紹了MySQL透明頁壓縮(TPC)批量取消與磁盤碎片優(yōu)化實戰(zhàn)的相關(guān)資料,本文通過真實案例,教你安全批量取消TPC并解決磁盤碎片,文中通過代碼介紹的非常詳細,需要的朋友可以參考下

引言:透明頁壓縮帶來的挑戰(zhàn)

MySQL的透明頁壓縮(Transparent Page Compression,簡稱TPC)是InnoDB提供的一種數(shù)據(jù)壓縮技術(shù),它可以在頁面級別對數(shù)據(jù)進行壓縮,從而減少磁盤空間占用。然而,在生產(chǎn)環(huán)境中,我們經(jīng)常發(fā)現(xiàn)TPC會帶來一些副作用:

  1. 磁盤碎片嚴重:頻繁的壓縮和解壓操作導致文件系統(tǒng)碎片增加
  2. 性能波動:壓縮/解壓消耗CPU資源,影響查詢性能
  3. 空間回收困難:即使刪除數(shù)據(jù),壓縮頁可能無法完全釋放空間

本文將通過一個實際案例,詳細介紹如何安全、高效地批量取消TPC,并優(yōu)化由此產(chǎn)生的磁盤碎片問題。

一、透明頁壓縮原理與問題分析

1.1 TPC工作原理

-- 創(chuàng)建使用TPC的表
CREATE TABLE tpc_table (
    id INT PRIMARY KEY,
    data VARCHAR(2000)
) COMPRESSION='zlib'  -- 啟用透明頁壓縮
  KEY_BLOCK_SIZE=8;    -- 指定壓縮頁大小

TPC在寫入時壓縮數(shù)據(jù)頁,讀取時解壓。每個壓縮頁都附帶一個"洞"(hole),通過fallocate()系統(tǒng)調(diào)用創(chuàng)建,實現(xiàn)空間節(jié)省。

1.2 常見問題癥狀

-- 檢查表空間碎片情況
SELECT 
    TABLE_SCHEMA,
    TABLE_NAME,
    DATA_LENGTH,
    INDEX_LENGTH,
    DATA_FREE,
    ROUND((DATA_FREE / (DATA_LENGTH + INDEX_LENGTH)) * 100, 2) AS fragmentation_percent
FROM information_schema.TABLES 
WHERE DATA_FREE > 1024 * 1024 * 100  -- 大于100MB的碎片
ORDER BY DATA_FREE DESC
LIMIT 10;

高碎片化會導致:

  • 磁盤I/O效率下降
  • 備份恢復時間增長
  • 磁盤空間虛高

二、實戰(zhàn)案例:批量取消TPC壓縮

2.1 環(huán)境準備與風險評估

案例背景

  • MySQL 8.0.28,InnoDB引擎
  • 數(shù)據(jù)庫大?。?TB,其中1.5TB使用TPC
  • 磁盤:NVMe SSD,但碎片率超過40%

風險評估清單

# 1. 檢查當前TPC使用情況
SELECT 
    COUNT(*) as tpc_tables,
    SUM(DATA_LENGTH/1024/1024/1024) as tpc_size_gb
FROM information_schema.TABLES 
WHERE CREATE_OPTIONS LIKE '%COMPRESSION=%';

# 2. 檢查InnoDB狀態(tài)
SHOW ENGINE INNODB STATUS\G

# 3. 監(jiān)控磁盤空間
df -h /var/lib/mysql
ls -lh /var/lib/mysql/*.ibd | sort -k5 -h -r | head -20

2.2 批量取消TPC方案設計

方案選擇對比

方法優(yōu)點缺點適用場景
ALTER TABLE … COMPRESSION=‘None’在線操作,業(yè)務影響小慢,產(chǎn)生大量redo log小型表,業(yè)務低峰期
邏輯導出導入(mysqldump)徹底消除碎片需要停機時間大型表,有維護窗口
表空間傳輸(Transportable Tablespaces)速度快,鎖時間短需要Percona工具超大表遷移

2.3 分步實施:中小型表在線取消

步驟1:生成批量取消腳本

-- 生成取消壓縮的SQL語句
SELECT 
    CONCAT(
        'ALTER TABLE `', TABLE_SCHEMA, '`.`', TABLE_NAME, '` ',
        'COMPRESSION="None", ',
        'KEY_BLOCK_SIZE=0;'
    ) as alter_sql,
    ROUND((DATA_LENGTH + INDEX_LENGTH)/1024/1024, 2) as size_mb
FROM information_schema.TABLES 
WHERE CREATE_OPTIONS LIKE '%COMPRESSION=%'
    AND (DATA_LENGTH + INDEX_LENGTH) < 1024 * 1024 * 1024  -- 小于1GB的表
ORDER BY size_mb ASC;

-- 生成進度監(jiān)控腳本
SELECT 
    TABLE_SCHEMA,
    TABLE_NAME,
    'SELECT "正在處理: ' || TABLE_SCHEMA || '.' || TABLE_NAME || '" as status; ' ||
    'ALTER TABLE `' || TABLE_SCHEMA || '`.`' || TABLE_NAME || '` COMPRESSION="None", KEY_BLOCK_SIZE=0;' ||
    'OPTIMIZE TABLE `' || TABLE_SCHEMA || '`.`' || TABLE_NAME || '`;' as full_process
FROM information_schema.TABLES 
WHERE CREATE_OPTIONS LIKE '%COMPRESSION=%';

步驟2:使用pt-online-schema-change平滑執(zhí)行

#!/bin/bash
# 批量取消TPC的自動化腳本

DB_HOST="localhost"
DB_USER="admin"
DB_PASS="your_password"
CHUNK_SIZE="100k"
MAX_LOAD="Threads_running=50"

# 獲取所有TPC表
mysql -h${DB_HOST} -u${DB_USER} -p${DB_PASS} -N -e "
SELECT CONCAT(TABLE_SCHEMA, '.', TABLE_NAME) 
FROM information_schema.TABLES 
WHERE CREATE_OPTIONS LIKE '%COMPRESSION=%'
    AND TABLE_SCHEMA NOT IN ('mysql', 'information_schema', 'performance_schema')
" > tpc_tables.txt

# 逐表處理
while read table; do
    echo "處理表: $table"
    
    pt-online-schema-change \
        --host=${DB_HOST} \
        --user=${DB_USER} \
        --password=${DB_PASS} \
        --alter="COMPRESSION='None', KEY_BLOCK_SIZE=0" \
        --chunk-size=${CHUNK_SIZE} \
        --max-load=${MAX_LOAD} \
        --execute \
        D=${table%.*},t=${table#*.}
    
    # 記錄日志
    echo "$(date): 已處理 $table" >> tpc_remove.log
    
    # 暫停60秒,避免對主庫影響過大
    sleep 60
done < tpc_tables.txt

2.4 大型表的特殊處理方案

對于超過100GB的大型表,我們采用表空間傳輸方案:

-- 1. 創(chuàng)建目標表結(jié)構(gòu)(無壓縮)
CREATE TABLE orders_new LIKE orders;
ALTER TABLE orders_new COMPRESSION='None', KEY_BLOCK_SIZE=0;

-- 2. 丟棄目標表空間
ALTER TABLE orders_new DISCARD TABLESPACE;

-- 3. 使用Percona工具復制表空間文件
# 在操作系統(tǒng)層面執(zhí)行
sudo innobackupex --compress --export /backup/orders/
sudo cp /backup/orders/orders.ibd /var/lib/mysql/mydb/orders_new.ibd
sudo cp /backup/orders/orders.cfg /var/lib/mysql/mydb/orders_new.cfg

-- 4. 導入表空間
ALTER TABLE orders_new IMPORT TABLESPACE;

-- 5. 驗證數(shù)據(jù)一致性
CHECK TABLE orders_new EXTENDED;

-- 6. 原子切換(在維護窗口進行)
RENAME TABLE orders TO orders_old, orders_new TO orders;

-- 7. 清理舊表(確認業(yè)務正常后)
DROP TABLE orders_old;

三、磁盤碎片優(yōu)化與空間回收

3.1 碎片檢測與評估

# 使用filefrag檢查物理碎片
sudo filefrag /var/lib/mysql/mydb/*.ibd | grep "extents found"

# MySQL內(nèi)部碎片統(tǒng)計
SELECT 
    TABLE_NAME,
    ENGINE,
    TABLE_ROWS,
    DATA_LENGTH,
    INDEX_LENGTH,
    DATA_FREE,
    ROUND((DATA_FREE / (DATA_LENGTH + INDEX_LENGTH + DATA_FREE)) * 100, 2) AS frag_ratio
FROM information_schema.TABLES 
WHERE TABLE_SCHEMA = 'mydb'
    AND DATA_FREE > 1024 * 1024 * 10  -- 10MB以上碎片
ORDER BY frag_ratio DESC;

3.2 優(yōu)化策略組合拳

策略1:OPTIMIZE TABLE(需要停機時間)

-- 針對碎片率超過30%的表
SET SESSION old_alter_table=1;  -- 使用舊算法,減少內(nèi)存使用

SELECT 
    CONCAT('OPTIMIZE TABLE `', TABLE_SCHEMA, '`.`', TABLE_NAME, '`;') as optimize_cmd
FROM information_schema.TABLES 
WHERE TABLE_SCHEMA = 'mydb'
    AND ROUND((DATA_FREE / (DATA_LENGTH + INDEX_LENGTH + DATA_FREE)) * 100, 2) > 30
    AND TABLE_ROWS > 1000000;

策略2:分批重建索引(在線操作)

-- 針對索引碎片
SELECT 
    TABLE_SCHEMA,
    TABLE_NAME,
    INDEX_NAME,
    ROUND(STAT_VALUE * @@innodb_page_size / 1024 / 1024, 2) AS index_size_mb
FROM mysql.innodb_index_stats 
WHERE STAT_NAME = 'size'
    AND DATABASE_NAME = 'mydb'
ORDER BY STAT_VALUE DESC
LIMIT 20;

-- 分批重建大索引
ALTER TABLE large_table DROP KEY idx_large, ADD KEY idx_large(column1, column2);
-- 使用ALGORITHM=INPLACE, LOCK=NONE在線重建

策略3:使用innodb_defragment在線整理

-- 啟用InnoDB碎片整理
SET GLOBAL innodb_defragment=1;
SET GLOBAL innodb_defragment_n_pages=7;
SET GLOBAL innodb_defragment_stats_accuracy=0;

-- 監(jiān)控整理進度
SELECT * FROM information_schema.INNODB_DEFRAG;

3.3 自動化維護腳本

#!/usr/bin/env python3
"""
MySQL TPC取消與碎片整理自動化腳本
"""

import pymysql
import subprocess
import logging
from datetime import datetime

class MySQLTPCOptimizer:
    def __init__(self, host, user, password):
        self.conn = pymysql.connect(
            host=host,
            user=user,
            password=password,
            charset='utf8mb4'
        )
        self.logger = self.setup_logger()
        
    def setup_logger(self):
        logging.basicConfig(
            level=logging.INFO,
            format='%(asctime)s - %(levelname)s - %(message)s',
            handlers=[
                logging.FileHandler('mysql_tpc_optimization.log'),
                logging.StreamHandler()
            ]
        )
        return logging.getLogger(__name__)
    
    def get_tpc_tables(self, min_size_mb=100):
        """獲取使用TPC的表"""
        sql = """
        SELECT 
            TABLE_SCHEMA,
            TABLE_NAME,
            ROUND((DATA_LENGTH + INDEX_LENGTH) / 1024 / 1024, 2) as size_mb,
            CREATE_OPTIONS
        FROM information_schema.TABLES 
        WHERE CREATE_OPTIONS LIKE '%COMPRESSION=%'
            AND (DATA_LENGTH + INDEX_LENGTH) > %s * 1024 * 1024
        ORDER BY size_mb DESC
        """
        
        with self.conn.cursor() as cursor:
            cursor.execute(sql, (min_size_mb,))
            return cursor.fetchall()
    
    def estimate_operation_time(self, table_size_mb):
        """估算操作時間(經(jīng)驗公式)"""
        # 導出導入:約 50 MB/s
        # 在線ALTER:約 20 MB/s
        export_time = table_size_mb / 50
        alter_time = table_size_mb / 20
        
        return {
            'export_import': export_time * 2,  # 導出+導入
            'online_alter': alter_time,
            'recommended': 'export_import' if table_size_mb > 10240 else 'online_alter'
        }
    
    def batch_remove_tpc(self, batch_size=5):
        """批量取消TPC"""
        tables = self.get_tpc_tables()
        
        for i in range(0, len(tables), batch_size):
            batch = tables[i:i+batch_size]
            self.logger.info(f"處理批次 {i//batch_size + 1}: {len(batch)}張表")
            
            for schema, table, size_mb, _ in batch:
                try:
                    self.logger.info(f"開始處理 {schema}.{table} ({size_mb}MB)")
                    
                    # 根據(jù)大小選擇策略
                    if size_mb > 10240:  # 大于10GB
                        self.handle_large_table(schema, table)
                    else:
                        self.handle_medium_table(schema, table)
                        
                    self.logger.info(f"完成處理 {schema}.{table}")
                    
                except Exception as e:
                    self.logger.error(f"處理 {schema}.{table} 失敗: {str(e)}")
                    continue
    
    def optimize_fragmentation(self, frag_threshold=20):
        """優(yōu)化碎片化嚴重的表"""
        sql = """
        SELECT 
            TABLE_SCHEMA,
            TABLE_NAME,
            ROUND((DATA_FREE / (DATA_LENGTH + INDEX_LENGTH + DATA_FREE)) * 100, 2) AS frag_ratio
        FROM information_schema.TABLES 
        WHERE TABLE_SCHEMA NOT IN ('mysql', 'sys', 'information_schema')
            AND DATA_FREE > 50 * 1024 * 1024  -- 大于50MB
            AND ROUND((DATA_FREE / (DATA_LENGTH + INDEX_LENGTH + DATA_FREE)) * 100, 2) > %s
        ORDER BY frag_ratio DESC
        """
        
        with self.conn.cursor() as cursor:
            cursor.execute(sql, (frag_threshold,))
            fragmented_tables = cursor.fetchall()
            
            for schema, table, frag_ratio in fragmented_tables:
                self.logger.info(f"優(yōu)化碎片表 {schema}.{table} (碎片率: {frag_ratio}%)")
                
                # 使用OPTIMIZE TABLE
                optimize_sql = f"OPTIMIZE TABLE `{schema}`.`{table}`"
                cursor.execute(optimize_sql)
                result = cursor.fetchone()
                
                self.logger.info(f"優(yōu)化結(jié)果: {result}")

if __name__ == "__main__":
    optimizer = MySQLTPCOptimizer(
        host="localhost",
        user="admin",
        password="your_password"
    )
    
    # 執(zhí)行TPC取消
    optimizer.batch_remove_tpc(batch_size=3)
    
    # 執(zhí)行碎片整理
    optimizer.optimize_fragmentation(frag_threshold=25)

四、監(jiān)控與驗證

4.1 監(jiān)控指標設計

-- 監(jiān)控視圖:TPC取消進度
CREATE VIEW tpc_removal_progress AS
SELECT 
    'before' as period,
    COUNT(*) as table_count,
    SUM(DATA_LENGTH + INDEX_LENGTH) as total_size
FROM information_schema.TABLES 
WHERE CREATE_OPTIONS LIKE '%COMPRESSION=%'
UNION ALL
SELECT 
    'after',
    COUNT(*),
    SUM(DATA_LENGTH + INDEX_LENGTH)
FROM information_schema.TABLES 
WHERE CREATE_OPTIONS NOT LIKE '%COMPRESSION=%' 
    OR CREATE_OPTIONS IS NULL;

-- 磁盤空間監(jiān)控
CREATE VIEW disk_usage_trend AS
SELECT 
    DATE(create_time) as date,
    SUM(CASE WHEN CREATE_OPTIONS LIKE '%COMPRESSION=%' THEN 1 ELSE 0 END) as tpc_tables,
    SUM(CASE WHEN CREATE_OPTIONS LIKE '%COMPRESSION=%' THEN DATA_LENGTH + INDEX_LENGTH ELSE 0 END) / 1024 / 1024 / 1024 as tpc_size_gb,
    AVG(DATA_FREE / (DATA_LENGTH + INDEX_LENGTH + DATA_FREE)) * 100 as avg_frag_percent
FROM information_schema.TABLES 
    CROSS JOIN (SELECT NOW() as create_time) as t
WHERE TABLE_SCHEMA = 'mydb'
GROUP BY DATE(create_time);

4.2 性能對比測試

-- 測試查詢性能變化
SELECT 
    'before_optimization' as phase,
    AVG(query_time) as avg_query_time,
    MAX(query_time) as max_query_time,
    COUNT(*) as query_count
FROM mysql.slow_log 
WHERE db = 'mydb'
    AND start_time < '2024-01-15'
UNION ALL
SELECT 
    'after_optimization',
    AVG(query_time),
    MAX(query_time),
    COUNT(*)
FROM mysql.slow_log 
WHERE db = 'mydb'
    AND start_time >= '2024-01-15';

-- I/O性能監(jiān)控
SHOW GLOBAL STATUS LIKE 'Innodb_data_reads';
SHOW GLOBAL STATUS LIKE 'Innodb_data_writes';
SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_reads';

五、經(jīng)驗總結(jié)與最佳實踐

5.1 關(guān)鍵經(jīng)驗總結(jié)

  1. 分批處理:不要一次性處理所有表,按大小分批次
  2. 監(jiān)控先行:執(zhí)行前建立完整監(jiān)控基線
  3. 回滾預案:隨時準備停止或回滾
  4. 業(yè)務影響評估:與業(yè)務團隊充分溝通時間窗口

5.2 TPC使用建議

適合使用TPC的場景

  • 只讀或讀多寫少的表
  • SSD存儲成本敏感的環(huán)境
  • 數(shù)據(jù)歸檔表

不適合使用TPC的場景

  • 高頻更新的OLTP表
  • 內(nèi)存充足,追求極致性能
  • 已經(jīng)使用其他壓縮方案(如InnoDB表壓縮)

5.3 長期維護策略

-- 定期碎片檢查任務
CREATE EVENT check_fragmentation
ON SCHEDULE EVERY 1 WEEK
STARTS CURRENT_TIMESTAMP
DO
BEGIN
    -- 記錄碎片狀態(tài)
    INSERT INTO frag_monitor_history
    SELECT NOW(), TABLE_SCHEMA, TABLE_NAME,
           ROUND((DATA_FREE / (DATA_LENGTH + INDEX_LENGTH + DATA_FREE)) * 100, 2)
    FROM information_schema.TABLES 
    WHERE TABLE_SCHEMA NOT IN ('mysql', 'sys')
        AND DATA_FREE > 100 * 1024 * 1024;
    
    -- 自動優(yōu)化高碎片表
    CALL auto_optimize_fragmented_tables(30); -- 30%閾值
END;

六、附錄:常用命令速查

# 1. 檢查表壓縮狀態(tài)
mysql -e "SHOW TABLE STATUS WHERE Comment LIKE '%Compressed%'\G"

# 2. 檢查文件系統(tǒng)碎片
sudo filefrag -v /var/lib/mysql/dbname/*.ibd | grep "extent"

# 3. 快速估算表大小
SELECT 
    table_name AS `Table`,
    ROUND(((data_length + index_length) / 1024 / 1024), 2) AS `Size (MB)`
FROM information_schema.TABLES
WHERE table_schema = "your_database"
ORDER BY (data_length + index_length) DESC;

# 4. 監(jiān)控ALTER進度(MySQL 8.0+)
SELECT * FROM performance_schema.events_stages_current 
WHERE EVENT_NAME LIKE 'stage/innodb/alter%';

總結(jié)

到此這篇關(guān)于MySQL透明頁壓縮(TPC)批量取消與磁盤碎片優(yōu)化實戰(zhàn)案例的文章就介紹到這了,更多相關(guān)MySQL透明頁壓縮批量取消內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • mysql如何設置主從數(shù)據(jù)庫的同步

    mysql如何設置主從數(shù)據(jù)庫的同步

    這篇文章主要介紹了mysql如何設置主從數(shù)據(jù)庫的同步問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-10-10
  • mysql中如何按分組添加序號

    mysql中如何按分組添加序號

    這篇文章主要介紹了mysql中如何按分組添加序號問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-06-06
  • 分享MySQL?主從延遲與讀寫分離的七種解決方案

    分享MySQL?主從延遲與讀寫分離的七種解決方案

    這篇文章主要介紹了分享MySQL?主從延遲與讀寫分離的七種解決方案,常見的解決方式是分庫分表,每次讀寫都是操作主庫的一個分表,從庫只用來做數(shù)據(jù)備份。當主庫發(fā)生故障時,主從切換,保證集群的高可用性,下面詳細的相關(guān)資料介紹,需要的小伙伴可以參考一下
    2022-03-03
  • mysql 5.7.17 winx64.zip安裝配置方法圖文教程

    mysql 5.7.17 winx64.zip安裝配置方法圖文教程

    這篇文章主要為大家分享了mysql 5.7.17 winx64.zip安裝配置方法圖文教程,具有一定的參考價值,感興趣的朋友可以參考一下
    2017-02-02
  • Mysql之如何修改字段名和字段類型

    Mysql之如何修改字段名和字段類型

    這篇文章主要介紹了Mysql之如何修改字段名和字段類型問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-07-07
  • Linux安裝mysql并配置外網(wǎng)訪問的實例

    Linux安裝mysql并配置外網(wǎng)訪問的實例

    今天小編就為大家分享一篇Linux安裝mysql并配置外網(wǎng)訪問的實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-05-05
  • MySQL索引失效原因及最左前綴匹配原則示例詳解

    MySQL索引失效原因及最左前綴匹配原則示例詳解

    這篇文章主要介紹了MySQL索引失效原因及最左前綴匹配原則示例,通過理解最左前綴原則和這些典型的索引失效場景,你可以更有效地設計索引、編寫高效的SQL查詢,并診斷性能問題,需要的朋友可以參考下
    2025-08-08
  • Mysql中關(guān)于Incorrect string value的解決方案

    Mysql中關(guān)于Incorrect string value的解決方案

    在對mysql數(shù)據(jù)庫中插入數(shù)據(jù)的時候,直接插入中文是沒有問題的!但是用預編譯語句時,用流對數(shù)據(jù)進行處理總報incorrect string value這個異常。本篇文章教給你解決方法
    2021-09-09
  • Mysql表連接的誤區(qū)與原理詳析

    Mysql表連接的誤區(qū)與原理詳析

    在使用MySQL數(shù)據(jù)庫過程中,left?join?基本是必用的語法,下面這篇文章主要給大家介紹了關(guān)于Mysql表連接的誤區(qū)與原理的相關(guān)資料,需要的朋友可以參考下
    2022-09-09
  • mysql 報錯 incompatible with sql_mode=only_full_group_by解決

    mysql 報錯 incompatible with sql_mode=only

    這篇文章主要為大家介紹了mysql 報錯 incompatible with sql_mode=only_full_group_by解決方法,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-10-10

最新評論

临高县| 阳谷县| 长岭县| 绥江县| 怀柔区| 扎兰屯市| 井冈山市| 蒲江县| 宁陵县| 景泰县| 长海县| 平定县| 福鼎市| 抚顺县| 平凉市| 乐都县| 舒兰市| 道真| 瑞昌市| 铜陵市| 彭水| 哈尔滨市| 旬阳县| 咸宁市| 来安县| 冀州市| 金阳县| 东港市| 安岳县| 时尚| 湖南省| 平遥县| 吉隆县| 应城市| 襄垣县| 嵊泗县| 石阡县| 庆阳市| 固阳县| 普兰店市| 三明市|