IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    给数据库做分表处理

    米粒在线发表于 2024-11-22 02:09:26
    love 0

    对于WordPress数据库的posts文章表很大,怎么优化是个头疼的问题。想到了分表就想尝试下。做个记录。原创记录文章,转载请注明出处。

    优化WordPress数据库中的posts表,可以从以下几个方面入手:

    删除不必要的数据:定期删除旧的文章和无用的数据,例如过期的草稿和已删除的文章。

    分表分区:如果posts表数据量很大,可以考虑分表分区,将数据按时间或其他逻辑划分到不同的表中。

    优化索引:确保表中的关键字段(如ID、post_date、post_title)有合适的索引,以提高查询效率。

    压缩数据:对于文本字段,可以考虑使用数据压缩技术,减少存储空间。

    使用缓存:利用缓存机制,减少对数据库的直接访问,提高系统性能。

    定期备份和修复:定期备份数据库,并使用修复工具检查并修复数据库中的错误。

    重点来研究下分表分区怎么做呢?   折腾之前做好备份先。

    将WordPress的posts表进行分表分区,可以显著提高性能,特别是对于数据量较大的情况下。以下是分表分区的一些步骤和方法:

    方法一:基于时间进行分区

    1. 创建分区表:
      • 通过基于时间(如年份、月份)来创建分区表,例如:
        SQL
        CREATE TABLE wp_posts (
          ID bigint(20) NOT NULL AUTO_INCREMENT,
          post_author bigint(20) NOT NULL,
          post_date datetime NOT NULL,
          ...
          PRIMARY KEY (ID)
        )
        PARTITION BY RANGE (YEAR(post_date)) (
          PARTITION p2019 VALUES LESS THAN (2020),
          PARTITION p2020 VALUES LESS THAN (2021),
          PARTITION p2021 VALUES LESS THAN (2022),
          PARTITION pmax VALUES LESS THAN MAXVALUE
        );
        

    方法二:基于哈希进行分区

    1. 使用哈希分区:
      • 通过哈希分区可以均匀分布数据,例如:
        SQL
        CREATE TABLE wp_posts (
          ID bigint(20) NOT NULL AUTO_INCREMENT,
          post_author bigint(20) NOT NULL,
          ...
          PRIMARY KEY (ID)
        )
        PARTITION BY HASH (ID) PARTITIONS 4;
        

    方法三:手动分表

    1. 创建多个表:
      • 可以手动创建多个表并根据条件将数据插入不同的表中。
    2. 编写触发器或应用层代码:
      • 编写触发器或在应用层(如WordPress插件或自定义代码)中实现数据分配逻辑。

    示例:手动分表和触发器

    1. 创建多个表:
      • 创建多个表例如wp_posts_2019,wp_posts_2020等。
    2. 创建触发器:
      • 编写触发器将数据分配到不同的表,例如:
        SQL
        CREATE TRIGGER insert_wp_posts
        BEFORE INSERT ON wp_posts
        FOR EACH ROW
        BEGIN
          IF NEW.post_date < '2020-01-01' THEN
            INSERT INTO wp_posts_2019 VALUES (NEW.*);
          ELSE
            INSERT INTO wp_posts_2020 VALUES (NEW.*);
          END IF;
        END;
        

    注意事项

    • 备份数据:在进行分区或分表之前,请确保备份数据,以防出现数据丢失。
    • 测试环境:在生产环境之前,先在测试环境中验证分区策略,以确保不会影响现有功能。
    • 维护计划:定期维护和监控分区表,确保其性能持续优化。

     

    有一些WordPress插件可以帮助实现数据库分片。以下插件:

    1. LudicrousDB: 这是一个高级数据库接口,支持复制、故障转移、负载均衡和分片。它基于Automattic的HyperDB插件,可以帮助你在多个数据库之间分片数据。
    2. HyperDB: 这是WordPress官方团队开发的插件,专为处理大规模数据库和分片而设计。它允许你通过配置文件来管理多个数据库连接。

    这些插件都可以帮助你实现数据库分片,提高网站性能。  但是相关资料比较少。

    关于LudicrousDB和HyperDB这两个WordPress插件,确实有些资料较少。这两个插件都是用于高级数据库接口,支持复制、故障转移、负载均衡和分区等功能。

    你可以参考以下资源来获取更多信息:

    • LudicrousDB GitHub页面:
    • CSDN博客文章:

    重点来试试折腾按年份给posts分表

    要按年份对 WordPress 的 posts 表进行分表,可以通过以下步骤来实现:

    1. 备份数据

    首先,务必备份现有数据库,以防止任何数据丢失。

    2. 创建新的分表

    根据年份创建新的分表。例如,如果你有 2019 年和 2020 年的帖子,可以创建两个分表 wp_posts_2019 和 wp_posts_2020。

    SQL

    CREATE TABLE wp_posts_2019 LIKE wp_posts;
    CREATE TABLE wp_posts_2020 LIKE wp_posts;
    

    3. 将数据迁移到分表

    将每年的数据迁移到相应的分表中。

    SQL

    INSERT INTO wp_posts_2019 SELECT * FROM wp_posts WHERE YEAR(post_date) = 2019;
    INSERT INTO wp_posts_2020 SELECT * FROM wp_posts WHERE YEAR(post_date) = 2020;
    

    4. 创建触发器

    创建触发器,将新的帖子根据年份插入到相应的分表中。

    SQL

    DELIMITER //
    
    CREATE TRIGGER before_insert_posts
    BEFORE INSERT ON wp_posts
    FOR EACH ROW
    BEGIN
      IF YEAR(NEW.post_date) = 2019 THEN
        INSERT INTO wp_posts_2019 SET ID=NEW.ID, post_author=NEW.post_author, post_date=NEW.post_date, ...;
      ELSEIF YEAR(NEW.post_date) = 2020 THEN
        INSERT INTO wp_posts_2020 SET ID=NEW.ID, post_author=NEW.post_author, post_date=NEW.post_date, ...;
      END IF;
    END//
    
    DELIMITER ;
    

    5. 修改查询逻辑

    修改 WordPress 的查询逻辑,使其根据年份从相应的分表中查询数据。可以通过编写插件或在 functions.php 文件中添加代码来实现。

    Php

    function custom_wp_query($query) {
        if (!is_admin() && $query->is_main_query()) {
            $year = date('Y');
            if ($year == 2019) {
                $query->set('table', 'wp_posts_2019');
            } else if ($year == 2020) {
                $query->set('table', 'wp_posts_2020');
            }
        }
    }
    add_action('pre_get_posts', 'custom_wp_query');
    

    注意事项

    • 备份数据:分表操作前一定要备份数据。
    • 测试环境:先在测试环境中进行分表操作,确保没有问题后再应用到生产环境。
    • 定期维护:定期维护和监控分表的性能,确保其优化效果。

    通过这些步骤,你可以将 posts 表按年份进行分表,从而提高数据库性能。

    但是以上举例2019、2020两个年份分表,后续的年份怎么处理呢?

    对于将来不断增加的年份,可以通过编写脚本或自动化流程来动态创建新的分表和相应的触发器。这样,每年都会自动处理新的数据分片,保持系统的良好性能。

    自动化处理新年份的分表

    以下是实现自动化分表的步骤:

    1. 创建一个 PHP 脚本来管理分表和触发器

    编写一个 PHP 脚本,检查当前年份,并根据需要创建新的分表和触发器。

    Php

    <?php
    function create_partition_table($year) {
        $table_name = 'wp_posts_' . $year;
        $create_table_sql = "CREATE TABLE IF NOT EXISTS $table_name LIKE wp_posts";
    
        $dbh = new PDO('mysql:host=localhost;dbname=your_db_name', 'your_db_user', 'your_db_password');
        $dbh->exec($create_table_sql);
    
        echo "Table $table_name created successfully.\n";
    }
    
    function create_trigger($year) {
        $trigger_name = "insert_wp_posts_$year";
        $table_name = 'wp_posts_' . $year;
    
        $create_trigger_sql = "
        CREATE TRIGGER $trigger_name
        BEFORE INSERT ON wp_posts
        FOR EACH ROW
        BEGIN
            IF YEAR(NEW.post_date) = $year THEN
                INSERT INTO $table_name SET NEW.*;
            END IF;
        END;
        ";
    
        $dbh = new PDO('mysql:host=localhost;dbname=your_db_name', 'your_db_user', 'your_db_password');
        $dbh->exec("DROP TRIGGER IF EXISTS $trigger_name");
        $dbh->exec($create_trigger_sql);
    
        echo "Trigger $trigger_name created successfully.\n";
    }
    
    // 获取当前年份并创建分表和触发器
    $current_year = date('Y');
    create_partition_table($current_year);
    create_trigger($current_year);
    ?>
    

    2. 定期运行脚本

    • 使用 cron 定时任务(Linux)或计划任务(Windows)定期运行脚本。你可以设置脚本每年初自动运行,以确保新的年份分表和触发器及时创建。

    3. 修改查询逻辑

    确保查询逻辑根据当前年份查询相应的分表。如果你已经按照之前的步骤修改了 functions.php 文件,那么每年的新分表将会自动生效。

    示例定时任务配置(Linux Cron)

    Sh

    # 每年1月1日凌晨0点执行一次脚本
    0 0 1 1 * /usr/bin/php /path/to/your/script/create_partition.php
    

    总结

    通过以上自动化处理,每年新的分表和触发器会自动创建,从而确保系统的性能和数据管理的可扩展性。自动化这些步骤,将会使你的系统更加灵活,并且长期维护起来也更为便捷。

    以下是总结的几个步骤:

    1. 创建 create_partition.php

    按照之前提供的代码创建 create_partition.php 脚本:

    Php

    <?php
    function create_partition_table($year) {
        $table_name = 'wp_posts_' . $year;
        $create_table_sql = "CREATE TABLE IF NOT EXISTS $table_name LIKE wp_posts";
    
        $dbh = new PDO('mysql:host=localhost;dbname=your_db_name', 'your_db_user', 'your_db_password');
        $dbh->exec($create_table_sql);
    
        echo "Table $table_name created successfully.\n";
    }
    
    function create_trigger($year) {
        $trigger_name = "insert_wp_posts_$year";
        $table_name = 'wp_posts_' . $year;
    
        $create_trigger_sql = "
        CREATE TRIGGER $trigger_name
        BEFORE INSERT ON wp_posts
        FOR EACH ROW
        BEGIN
            IF YEAR(NEW.post_date) = $year THEN
                INSERT INTO $table_name SET NEW.*;
            END IF;
        END;
        ";
    
        $dbh = new PDO('mysql:host=localhost;dbname=your_db_name', 'your_db_user', 'your_db_password');
        $dbh->exec("DROP TRIGGER IF EXISTS $trigger_name");
        $dbh->exec($create_trigger_sql);
    
        echo "Trigger $trigger_name created successfully.\n";
    }
    
    // 获取当前年份并创建分表和触发器
    $current_year = date('Y');
    create_partition_table($current_year);
    create_trigger($current_year);
    ?>
    

    2. 修改 functions.php

    在 functions.php 文件中添加代码来自动路由查询到相应的分表:

    Php

    function custom_wp_query($query) {
        if (!is_admin() && $query->is_main_query()) {
            $year = date('Y');
            $table_suffix = 'wp_posts_' . $year;
    
            // 使用全局 $wpdb 对象来设置自定义查询
            global $wpdb;
            $wpdb->posts = $table_suffix;
        }
    }
    add_action('pre_get_posts', 'custom_wp_query');
    

    3. 定时任务(Cron Job)

    设置一个定时任务来每年创建新的分表和触发器。

    在 Linux 上使用 Cron Job:

    1. 打开 crontab 配置:
      sh
      crontab -e
      
    2. 添加一条命令,每年1月1日运行脚本:
      sh
      0 0 1 1 * /usr/bin/php /path/to/your/script/create_partition.php
      

    4. 执行数据迁移(一次性操作)

    将现有的数据迁移到相应的分表中:

    sql
    -- 迁移2019年的数据
    INSERT INTO wp_posts_2019 SELECT * FROM wp_posts WHERE YEAR(post_date) = 2019;
    
    -- 迁移2020年的数据
    INSERT INTO wp_posts_2020 SELECT * FROM wp_posts WHERE YEAR(post_date) = 2020;
    
    -- 为每个分表执行类似的操作
    

    5. 检查并测试

    1. 验证分表:检查各个分表,确认数据已正确迁移。
    2. 测试触发器:添加新文章,确认其根据年份插入到正确的分表中。
    3. 测试查询:在前端访问网站,确保查询正确路由到相应的分表。

    通过这些步骤,你就可以在 WordPress 上实现按年份分表,从而提高数据库性能。

    以上仅作记录,折腾数据库之前做好备份。才有机会恢复。

    这样分表之后,数据库查询的效率和速度一般会得到显著提升。以下是分表优化的几个关键点:

    优化点

    1. 减少锁争用:
      • 分表将数据分散到不同的物理表中,减少了每个表上同时进行读写操作的冲突,从而提升了数据库的并发处理能力。
    2. 提高查询效率:
      • 查询范围缩小。每个查询只需要在相应的分表中进行,而不是在包含所有数据的大表中,减少了扫描的数据量,从而加快了查询速度。
    3. 更好的索引使用:
      • 更小的表使得索引更加高效,能更快速地查找到需要的数据。
    4. 优化缓存命中率:
      • 分表后,表的数据量变小,更容易将表的热数据(常用数据)缓存到内存中,提高了缓存的命中率。

    实际效果

    • 读操作:由于每次查询的数据量减少,数据库能够更快速地检索到所需的数据,尤其是在访问特定年份的数据时,性能提升会更加明显。
    • 写操作:由于减少了表的锁争用,写操作的性能也会得到改善。
    • 整体性能:分表降低了单表的数据量,使得数据库的维护和管理更为高效,特别是对于定期的备份、恢复和优化操作。

    监控与验证

    在实施分表优化后,建议通过以下方式进行监控和验证:

    • 监控查询性能:使用数据库的查询日志和性能监控工具,观察查询时间的变化。
    • 测试负载:在分表之前和之后进行负载测试,比较性能指标,如响应时间、CPU使用率和IO操作。
    • 用户反馈:观察用户访问速度和体验的变化。

    总体来说,分表是一种有效的数据库优化策略,特别是在处理大规模数据时。


    假如postmeta这个表也挺大的想做分表处理,也可以尝试下:

    postmeta 表也可以进行分表优化。这对于处理大量元数据非常有帮助,特别是当 postmeta 表变得很大时,优化查询性能尤为重要。

    按时间分表 postmeta

    假设我们按年份对 postmeta 表进行分表,步骤类似于 posts 表的分表操作。

    1. 创建 create_partition_postmeta.php 脚本

    创建一个类似的 PHP 脚本来管理 postmeta 表的分表和触发器:

    php
    <?php
    function create_partition_table($year) {
        $table_name = 'wp_postmeta_' . $year;
        $create_table_sql = "CREATE TABLE IF NOT EXISTS $table_name LIKE wp_postmeta";
    
        $dbh = new PDO('mysql:host=localhost;dbname=your_db_name', 'your_db_user', 'your_db_password');
        $dbh->exec($create_table_sql);
    
        echo "Table $table_name created successfully.\n";
    }
    
    function create_trigger($year) {
        $trigger_name = "insert_wp_postmeta_$year";
        $table_name = 'wp_postmeta_' . $year;
    
        $create_trigger_sql = "
        CREATE TRIGGER $trigger_name
        BEFORE INSERT ON wp_postmeta
        FOR EACH ROW
        BEGIN
            DECLARE post_year INT;
            SELECT YEAR(post_date) INTO post_year FROM wp_posts WHERE ID = NEW.post_id;
            IF post_year = $year THEN
                INSERT INTO $table_name SET NEW.*;
            END IF;
        END;
        ";
    
        $dbh = new PDO('mysql:host=localhost;dbname=your_db_name', 'your_db_user', 'your_db_password');
        $dbh->exec("DROP TRIGGER IF EXISTS $trigger_name");
        $dbh->exec($create_trigger_sql);
    
        echo "Trigger $trigger_name created successfully.\n";
    }
    
    // 获取当前年份并创建分表和触发器
    $current_year = date('Y');
    create_partition_table($current_year);
    create_trigger($current_year);
    ?>
    

    2. 修改 functions.php

    在 functions.php 文件中添加代码来自动路由 postmeta 查询到相应的分表:

    php
    function custom_wp_query_postmeta($query) {
        if (!is_admin() && $query->is_main_query()) {
            $year = date('Y');
            $postmeta_table_suffix = 'wp_postmeta_' . $year;
    
            // 使用全局 $wpdb 对象来设置自定义查询
            global $wpdb;
            $wpdb->postmeta = $postmeta_table_suffix;
        }
    }
    add_action('pre_get_posts', 'custom_wp_query_postmeta');
    

    3. 定时任务(Cron Job)

    设置一个定时任务来每年创建新的 postmeta 分表和触发器。

    在 Linux 上使用 Cron Job:

    1. 打开 crontab 配置:
      sh
      crontab -e
      
    2. 添加一条命令,每年1月1日运行脚本:
      sh
      0 0 1 1 * /usr/bin/php /path/to/your/script/create_partition_postmeta.php
      

    4. 执行数据迁移(一次性操作)

    将现有的 postmeta 数据迁移到相应的分表中:

    sql
    -- 迁移2019年的数据
    INSERT INTO wp_postmeta_2019 SELECT * FROM wp_postmeta WHERE post_id IN (SELECT ID FROM wp_posts WHERE YEAR(post_date) = 2019);
    
    -- 迁移2020年的数据
    INSERT INTO wp_postmeta_2020 SELECT * FROM wp_postmeta WHERE post_id IN (SELECT ID FROM wp_posts WHERE YEAR(post_date) = 2020);
    
    -- 为每个分表执行类似的操作
    

    5. 检查并测试

    1. 验证分表:检查各个分表,确认数据已正确迁移。
    2. 测试触发器:添加新文章及元数据,确认其根据年份插入到正确的分表中。
    3. 测试查询:在前端访问网站,确保查询正确路由到相应的分表。

    通过这些步骤,你可以将 postmeta 表按年份进行分表,从而提高数据库性能和查询效率。

    也就是我创建了两个php文件,就是create_partition_postmeta.php和create_partition.php 往functions.php 加入了两段代码。设置了定时任务两条。来进行对posts和postmeta两个表分表优化。

    步骤总结:

    1. 创建 PHP 脚本文件:
      • create_partition.php:管理 posts 表的分表和触发器。
      • create_partition_postmeta.php:管理 postmeta 表的分表和触发器。
    2. 修改 functions.php 文件:
      • 为 posts 表分表路由添加代码:
        php
        function custom_wp_query($query) {
            if (!is_admin() && $query->is_main_query()) {
                $year = date('Y');
                $table_suffix = 'wp_posts_' . $year;
        
                // 使用全局 $wpdb 对象来设置自定义查询
                global $wpdb;
                $wpdb->posts = $table_suffix;
            }
        }
        add_action('pre_get_posts', 'custom_wp_query');
        
      • 为 postmeta 表分表路由添加代码:
        php
        function custom_wp_query_postmeta($query) {
            if (!is_admin() && $query->is_main_query()) {
                $year = date('Y');
                $postmeta_table_suffix = 'wp_postmeta_' . $year;
        
                // 使用全局 $wpdb 对象来设置自定义查询
                global $wpdb;
                $wpdb->postmeta = $postmeta_table_suffix;
            }
        }
        add_action('pre_get_posts', 'custom_wp_query_postmeta');
        
    3. 设置定时任务(Cron Job):
      • 每年1月1日运行 create_partition.php 脚本:
        sh
        0 0 1 1 * /usr/bin/php /path/to/your/script/create_partition.php
        
      • 每年1月1日运行 create_partition_postmeta.php 脚本:
        sh
        0 0 1 1 * /usr/bin/php /path/to/your/script/create_partition_postmeta.php
        
    4. 执行数据迁移(一次性操作):
      • 将现有 posts 表的数据迁移到相应的分表中:
        sql
        INSERT INTO wp_posts_2019 SELECT * FROM wp_posts WHERE YEAR(post_date) = 2019;
        INSERT INTO wp_posts_2020 SELECT * FROM wp_posts WHERE YEAR(post_date) = 2020;
        
      • 将现有 postmeta 表的数据迁移到相应的分表中:
        sql
        INSERT INTO wp_postmeta_2019 SELECT * FROM wp_postmeta WHERE post_id IN (SELECT ID FROM wp_posts WHERE YEAR(post_date) = 2019);
        INSERT INTO wp_postmeta_2020 SELECT * FROM wp_postmeta WHERE post_id IN (SELECT ID FROM wp_posts WHERE YEAR(post_date) = 2020);
        

    检查与验证:

    • 验证分表和触发器:确保新文章和其元数据根据年份插入正确的分表。
    • 测试前端查询:确认前端查询正确路由到相应的分表。


沪ICP备19023445号-2号
友情链接