2

我有一个 mysql 表,我需要将其分成两个。目前,该表包含有关两个松散相关实体的信息。例如,实体可以是公司的员工和他被标记到的公司的笔记本电脑。下表解释了我的示例。我有一个employee包含以下列的表

employee_id,employee_name,employee_detail,join_date,laptop_id,laptop_type,laptop_tagged_date,laptop_details,laptop_make.

我需要将此表拆分为 2,如下所示。 employee没有笔记本电脑列的表

employee_id,employee_name,employee_detail,join_date.

laptop以employee_id 为键的新表。

employee_id,laptop_id,laptop_type,laptop_tagged_date,laptop_details,laptop_make

以下陈述适用于当前的数据库设计

  • employee表被后端代码大量使用。后端代码是用java和php编写的。
  • employee无法重命名表。意味着我不想创建 2 个新表。我想保留该employee表,但从中删除所有笔记本电脑信息。
  • 添加新行/现有行每天更新。

我的问题是

  1. 是否有一种设计方法可以让我从当前的单表设计平滑过渡到新建议的设计?
  2. 是否有任何最佳实践可遵循以确保顺利过渡。
  3. 您能否建议/重新指导我完成此任务的步骤。
4

3 回答 3

2
  1. 备份现有数据库:

    mysqldump my_db > backup.sql
    
  2. 创建一个新的laptop(我没有在下面的示例中定义索引或外键约束,但您应该做任何适合您的数据结构的事情):

    CREATE TABLE laptop
    SELECT employee_id,
           laptop_id,
           laptop_type,
           laptop_tagged_date,
           laptop_details,
           laptop_make
    FROM   employee
    WHERE  FALSE;
    
  3. 在原始表上定义触发器以将每种类型的写入操作(插入/更新/删除)转发到新表:

    CREATE TRIGGER employee_insert AFTER INSERT ON employee FOR EACH ROW
      INSERT INTO laptop VALUES (
        NEW.employee_id,
        NEW.laptop_id,
        NEW.laptop_type,
        NEW.laptop_tagged_date,
        NEW.laptop_details,
        NEW.laptop_make
      );
    
    CREATE TRIGGER employee_update AFTER UPDATE ON employee FOR EACH ROW
      UPDATE laptop SET
        employee_id         =  NEW.employee_id,
        laptop_id           =  NEW.laptop_id,
        laptop_type         =  NEW.laptop_type,
        laptop_tagged_date  =  NEW.laptop_tagged_date,
        laptop_details      =  NEW.laptop_details,
        laptop_make         =  NEW.laptop_make
      WHERE
        employee_id        <=> OLD.employee_id,
        laptop_id          <=> OLD.laptop_id,
        laptop_type        <=> OLD.laptop_type,
        laptop_tagged_date <=> OLD.laptop_tagged_date,
        laptop_details     <=> OLD.laptop_details,
        laptop_make        <=> OLD.laptop_make;
    
    CREATE TRIGGER employee_delete AFTER DELETE ON employee FOR EACH ROW
      DELETE FROM laptop WHERE
        employee_id        <=> OLD.employee_id,
        laptop_id          <=> OLD.laptop_id,
        laptop_type        <=> OLD.laptop_type,
        laptop_tagged_date <=> OLD.laptop_tagged_date,
        laptop_details     <=> OLD.laptop_details,
        laptop_make        <=> OLD.laptop_make;
    
  4. 清空新表(触发器已插入的任何内容),然后在同一个事务中,使用INSERT ... SELECT将原始表中的所有现有数据复制到其中:

    START TRANSACTION;
    
    DELETE FROM laptop;
    INSERT INTO laptop
    SELECT employee_id,
           laptop_id,
           laptop_type,
           laptop_tagged_date,
           laptop_details,
           laptop_make
    FROM   employee;
    
    COMMIT;
    
  5. 彻底搜索您的代码库(包括数据库存储的程序)以查找访问原始表中的笔记本电脑列的所有操作。注意是否每次操作:

    • 仅从这些列中读取;

    • 只写入那些列;或者

    • 读取和写入这些列(例如UPDATE employee SET laptop_tagged_date = laptop_tagged_date + INTERVAL 1 WEEK WHERE ...)。

  6. 修改读取操作以使用新表,将读取和写入操作拆分为单独的步骤(例如UPDATE employee JOIN laptop ON ... SET employee.laptop_tagged_date = laptop.laptop_tagged_date + INTERVAL 1 WEEK WHERE ...)。

    这种更改不需要原子地影响,因为原始表和新表将通过触发器保持同步:因此,应用程序的某些部分可以从新表中读取,而其他部分继续使用原始表。

    在您对该步骤已完成感到满意之前不要继续下一步,因为下一步将导致表变得不同步。您甚至可以使用 MySQL 用户权限来阻止写入新表(触发器除外),直到您对该步骤完成感到满意为止。

  7. 修改写操作以使用新表。

    此更改不需要原子地影响,因为对原始表的任何写入都将由触发器转发到新表:因此,应用程序的某些部分可以写入新表,而其他部分继续写入原始表。

  8. 从原始表中删除列:

    ALTER TABLE employee
      DROP COLUMN laptop_id,
      DROP COLUMN laptop_type,
      DROP COLUMN laptop_tagged_date,
      DROP COLUMN laptop_details,
      DROP COLUMN laptop_make;
    
于 2012-09-13T14:17:54.850 回答
1

如果您想拥有 2 个不同的物理表,您可以调整 Sebastien M. 的答案:

创建一个带有相应数据的笔记本电脑表以将它们外部化

CREATE TABLE laptop AS
SELECT DISTINCT employee_id,laptop_id,laptop_type,laptop_tagged_date,laptop_details,laptop_make
FROM employee
WHERE ...

提供一个employee_laptop 视图来模仿员工的行为并获得向后兼容性

create view employee_laptop as 
select employee_id, e.employee_name,e.employee_detail,e.join_date,
       l.laptop_id,l.laptop_type,l.laptop_tagged_date,l.laptop_details,l.laptop_make
from employee e join laptop l using(employee_id);

那么你就有足够的空间从员工表中删除不必要的列

于 2012-09-13T12:38:37.283 回答
1

我可以建议您一种可能的方法,当您创建laptop表时使用以下查询类型:-

create table laptop select employee_id,laptop_id,laptop_type,
laptop_tagged_date,laptop_details,laptop_make from
employee;

laptop在上述过程中创建表后,您可以从employee表中删除指定的列,以获取具有相关字段的新员工表。

从表中删除列employee

alter table employee
drop column laptop_id,laptop_type,laptop_tagged_date,laptop_details,laptop_make;

现在新employee表有以下字段:

employee_id,employee_name,employee_detail,join_date

现在该laptop表具有以下字段:

mployee_id,laptop_id,laptop_type,
    laptop_tagged_date,laptop_details,laptop_make

希望它会帮助你。

于 2012-09-13T13:34:20.620 回答