背景

由于需要某个页面有大量数据的时候,访问的情况性能如何,因此需要造一亿的数据。

现在ai辅助已经很强大了,一些脚本的文件其实可以直接让其生成,再微改。重要的是,想AI提问的方式,要符合自己的要求,包括一些细节方面的事情。

过程

确认表与表结构、字段类型

找研发确认需要造数的业务表,以及确认表之间的关联关系,以及对应的字段类型。

如下,拿到了三个表,

表message_cot

-- datasense_copilot_new.message_cot definition

CREATE TABLE `message_cot` (
  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
  `tenant_id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '租户ID',
  `creator` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '创建人',
  `created_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
  `editor` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '修改人',
  `updated_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '修改时间',
  `remarks` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '备注',
  `state` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'normal' COMMENT '状态:normal;deleted',
  `msg_id` bigint NOT NULL COMMENT '消息ID',
  `content` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '内容',
  `user_cot_content` text COLLATE utf8mb4_unicode_ci COMMENT '用户思索链',
  PRIMARY KEY (`id`) USING BTREE,
  KEY `msg_id_index` (`msg_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=50626 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='思索链表';

表message

-- datasense_copilot_new.message definition

CREATE TABLE `message` (
  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
  `tenant_id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '租户ID',
  `creator` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '创建人',
  `created_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
  `editor` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '修改人',
  `updated_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '修改时间',
  `remarks` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '备注',
  `state` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'normal' COMMENT '状态:normal;deleted',
  `conversation_id` bigint NOT NULL COMMENT '会话ID',
  `parent_id` bigint DEFAULT NULL COMMENT '父ID',
  `author` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `creator_nickname` varchar(119) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `question` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '问题',
  `content` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT '回复内容',
  `author_is_user` tinyint(1) DEFAULT '0',
  `feedback` int DEFAULT '0' COMMENT '反馈:0-无;-1-点踩;1-点赞;',
  `feedback_user` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '反馈人员',
  `action_type` int DEFAULT '0' COMMENT '无动作,正常消息:0-无;1:动作-召回指标;2-动作推荐问题',
  `mql` json DEFAULT NULL COMMENT '查询MQL内容',
  `action_content` json DEFAULT NULL COMMENT '动作内容',
  `final_question` text COLLATE utf8mb4_unicode_ci COMMENT '最终问题',
  `question_type` int DEFAULT '0' COMMENT '0:正常用户提问;1:召回指标;2:推荐问题',
  `message_status` tinyint NOT NULL DEFAULT '0' COMMENT '消息状态: 0-正常;1-异常;2-拒答;3-召回;',
  `feedback_type` json DEFAULT NULL COMMENT '反馈类型',
  `feedback_comment` varchar(512) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '反馈内容',
  `indicator` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '指标名称',
  `intention_status` int DEFAULT '0' COMMENT '0:意图正常,1:意图异常',
  `resultData` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci,
  `recommend_question` varchar(1024) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '用户选择推荐问题',
  `querySql` longtext COLLATE utf8mb4_unicode_ci COMMENT '查询sql',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=115017 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='消息表';

-- datasense_copilot_new.conversation definition

CREATE TABLE `conversation` (
  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
  `tenant_id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '租户ID',
  `creator` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '创建人',
  `created_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
  `editor` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '修改人',
  `updated_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '修改时间',
  `remarks` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '备注',
  `state` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'normal' COMMENT '状态:normal;deleted',
  `app_user_id` bigint NOT NULL,
  `title` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '会话标题',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1050 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='会话表';

表关联关系:

message.id = message_cot.msg_id

conversation.id = message.conversation_id

表关联关系:

message.id = message_cot.msg_id

conversation.id = message.conversation_id。

其中,message:message_cot是2:1的关系,conversation:message是1:多的关系

选择生成数方式

  1. 通过python脚本直接连接数据库,批量插入生成,适用于数据量在100-200w以内,非宽表生成
  2. 通过python生成对应的csv文件,然后直接导入mysql,适用于大数据量生成

这里采用的是方式2。

生成csv文件代码

现在ai辅助已经很强大了,一些脚本的文件其实可以直接让其生成,再微改。重要的是,想AI提问的方式,要符合自己的要求,包括一些细节方面的事情。

import csv
import random
from datetime import datetime, timedelta
import time
import sys

# 配置参数
conversation_count = 500000
message_count = 10_000_000
cot_count = 5_000_000
tenants = ['fastdata', 'tenant2', 'tenant3']
users = [f'user{i}' for i in range(1, 1001)]

# 中文问题生成组件
time_frames = ["今日", "本周", "本月", "本季度", "近三年", "去年", "前年", "最近三个月"]
metrics = ["销售额", "销售量", "产量", "利润", "客流量", "库存量", "退货量", "用户数"]
entities = ["张三", "李四", "王五", "销售部", "生产部", "华东区", "旗舰店", "线上渠道"]
verbs = ["的", "有多少", "是多少", "的统计", "的汇总", "的趋势", "的情况"]


def generate_chinese_question():
    """生成随机中文业务问题"""
    time = random.choice(time_frames)
    metric = random.choice(metrics)
    entity = random.choice(entities)
    verb = random.choice(verbs)

    pattern = random.choice([
        f"{time}{entity}的{metric}{verb}?",
        f"{time}{metric}{verb}?",
        f"{entity}{time}{metric}{verb}?",
        f"{metric}{verb}({time})?",
        f"{time}各{entity}的{metric}对比?"
    ])
    return pattern


# 进度跟踪工具类
class ProgressTracker:
    def __init__(self, total, name="Progress"):
        self.total = total
        self.name = name
        self.start_time = time.time()
        self.last_report = 0
        self.counter = 0

    def update(self, current):
        self.counter = current
        now = time.time()
        # 控制刷新频率:每1%或至少5秒更新一次
        if current == self.total or (now - self.last_report) > 5 or (
                current / self.total - self.last_report / self.total) >= 0.01:
            elapsed = now - self.start_time
            percent = current / self.total * 100
            speed = current / elapsed if elapsed > 0 else 0
            eta = (self.total - current) / speed if speed > 0 else 0

            sys.stdout.write(
                f"\r{self.name}: {percent:.1f}% | "
                f"已处理: {current}/{self.total} | "
                f"速度: {speed:.1f} rows/s | "
                f"已用: {timedelta(seconds=int(elapsed))} | "
                f"剩余: {timedelta(seconds=int(eta))}      "
            )
            sys.stdout.flush()
            self.last_report = now


# 生成 conversation.csv
print("\n生成会话数据...")
with open('conversation.csv', 'w', newline='', encoding='utf-8') as f:
    writer = csv.writer(f)
    writer.writerow(
        ['id', 'tenant_id', 'creator', 'created_at', 'editor', 'updated_at', 'remarks', 'state', 'app_user_id',
         'title'])

    tracker = ProgressTracker(conversation_count, "Conversation")
    for c_id in range(1, conversation_count + 1):
        tenant = tenants[c_id % len(tenants)]
        creator = users[c_id % len(users)]
        created_at = (datetime(2023, 1, 1) + timedelta(
            days=random.randint(0, 365),
            seconds=random.randint(0, 86400))
                      ).strftime('%Y-%m-%d %H:%M:%S.%f')[:-3]

        writer.writerow([
            c_id,
            tenant,
            creator,
            created_at,
            creator,
            created_at,
            f'Remark {c_id}',
            'normal',
            random.randint(1000, 9999),
            f'Conversation {c_id}'
        ])
        tracker.update(c_id)
    print("\n会话数据生成完成")

# 生成 message.csv
print("\n生成消息数据...")
with open('message.csv', 'w', newline='', encoding='utf-8') as f:
    writer = csv.writer(f)
    writer.writerow(
        ['id', 'tenant_id', 'creator', 'created_at', 'editor', 'updated_at', 'remarks', 'state', 'conversation_id',
         'parent_id', 'author', 'creator_nickname', 'question', 'content', 'author_is_user', 'feedback',
         'feedback_user', 'action_type', 'mql', 'action_content', 'final_question', 'question_type', 'message_status',
         'feedback_type', 'feedback_comment', 'indicator', 'intention_status', 'resultData', 'recommend_question',
         'querySql'])

    tracker = ProgressTracker(message_count, "Messages")
    for msg_id in range(1, message_count + 1):
        is_parent = msg_id % 2 == 1
        c_id = (msg_id - 1) // 20 + 1

        question = generate_chinese_question() if is_parent else None

        tenant = tenants[c_id % len(tenants)]
        creator = users[c_id % len(users)]
        created_at = (datetime(2023, 1, 1) + timedelta(
            days=random.randint(0, 365),
            seconds=random.randint(0, 86400))
                      ).strftime('%Y-%m-%d %H:%M:%S.%f')[:-3]

        parent_id = None if is_parent else msg_id - 1

        writer.writerow([
            msg_id,
            tenant,
            creator,
            created_at,
            creator,
            created_at,
            f'Msg Remark {msg_id}',
            'normal',
            c_id,
            parent_id,
            'Copilot' if is_parent else 'User',
            f'{creator}_nick',
            question,
            f'Content {msg_id}' if not is_parent else None,
            0 if is_parent else 1,
            0,
            None,
            0,
            None,
            None,
            None,
            0,
            0,
            None,
            None,
            '交易金额' if is_parent else None,
            0,
            None,
            None,
            None
        ])
        tracker.update(msg_id)
    print("\n消息数据生成完成")

# 生成 message_cot.csv
print("\n生成COT数据...")
with open('message_cot.csv', 'w', newline='', encoding='utf-8') as f:
    writer = csv.writer(f)
    writer.writerow(
        ['id', 'tenant_id', 'creator', 'created_at', 'editor', 'updated_at', 'remarks', 'state', 'msg_id', 'content',
         'user_cot_content'])

    tracker = ProgressTracker(cot_count, "COTs")
    for cot_id in range(1, cot_count + 1):
        msg_id = 2 * cot_id - 1
        c_id = (msg_id - 1) // 20 + 1
        tenant = tenants[c_id % len(tenants)]
        creator = users[c_id % len(users)]
        created_at = (datetime(2023, 1, 1) + timedelta(
            days=random.randint(0, 365),
            seconds=random.randint(0, 86400))
                      ).strftime('%Y-%m-%d %H:%M:%S.%f')[:-3]

        writer.writerow([
            cot_id,
            tenant,
            creator,
            created_at,
            creator,
            created_at,
            f'COT Remark {cot_id}',
            'normal',
            msg_id,
            f'COT Content {cot_id}',
            f'User COT {cot_id}'
        ])
        tracker.update(cot_id)
    print("\nCOT数据生成完成")

print("\n所有数据生成完成!")

导入数据库

这里踩坑的一点:容器部署的MySQL与非容器部署的不一样。若是在容器内部署的,需要进入容器里面执行,并且进入容器的时候,要加上–local-infile,否则会报错拒绝。

加上之后就可以正常导入了:

导入前准备:

-- 1. 登录 MySQL(需有 FILE 权限和足够权限)
mysql -u root -p

-- 2. 创建数据库(若不存在)
CREATE DATABASE IF NOT EXISTS datasense_copilot_new 
DEFAULT CHARACTER SET utf8mb4 
COLLATE utf8mb4_unicode_ci;

-- 3. 确认表结构已存在(需与CSV字段顺序完全一致)
-- 此处需执行你提供的三个 CREATE TABLE 语句

导入过程:

-- 禁用约束和索引(提速关键)
SET FOREIGN_KEY_CHECKS = 0;
SET UNIQUE_CHECKS = 0;
SET AUTOCOMMIT = 0;
SET sql_log_bin = 0;  -- 如果不需要binlog

-- 导入 conversation
ALTER TABLE conversation DISABLE KEYS;
LOAD DATA LOCAL INFILE '/绝对路径/conversation.csv' 
INTO TABLE conversation
CHARACTER SET utf8mb4
FIELDS TERMINATED BY ',' 
OPTIONALLY ENCLOSED BY '"'
LINES TERMINATED BY '\n'
IGNORE 1 ROWS;
ALTER TABLE conversation ENABLE KEYS;

-- 导入 message(耗时最长)
ALTER TABLE message DISABLE KEYS;
LOAD DATA LOCAL INFILE '/绝对路径/message.csv' 
INTO TABLE message
CHARACTER SET utf8mb4
FIELDS TERMINATED BY ',' 
OPTIONALLY ENCLOSED BY '"'
LINES TERMINATED BY '\n'
IGNORE 1 ROWS;
ALTER TABLE message ENABLE KEYS;

-- 导入 message_cot
ALTER TABLE message_cot DISABLE KEYS;
LOAD DATA LOCAL INFILE '/绝对路径/message_cot.csv' 
INTO TABLE message_cot
CHARACTER SET utf8mb4
FIELDS TERMINATED BY ',' 
OPTIONALLY ENCLOSED BY '"'
LINES TERMINATED BY '\n'
IGNORE 1 ROWS;
ALTER TABLE message_cot ENABLE KEYS;

-- 恢复设置
SET FOREIGN_KEY_CHECKS = 1;
SET UNIQUE_CHECKS = 1;
COMMIT;
SET AUTOCOMMIT = 1;
SET sql_log_bin = 1;

-- 优化表结构(可选)
ANALYZE TABLE conversation, message, message_cot;


参数说明推荐值
<font style="color:rgb(64, 64, 64);">LOCAL</font>从客户端机器读取文件(否则需服务端路径权限)必须与文件位置匹配
<font style="color:rgb(64, 64, 64);">CHARACTER SET</font>字符集需与CSV文件一致utf8mb4
<font style="color:rgb(64, 64, 64);">FIELDS TERMINATED</font>字段分隔符,
<font style="color:rgb(64, 64, 64);">LINES TERMINATED</font>行终止符\n(Windows需\r\n)
<font style="color:rgb(64, 64, 64);">IGNORE 1 ROWS</font>跳过CSV标题行根据实际文件调整

执行之后,等待执行完就好了。

预计总导入时间在:

  • 普通机械硬盘:约2-3小时
  • SSD硬盘:约30-60分钟
  • 内存盘:约10-20分钟

查看是否导入成功

直接select count(1) * table_name; 查看数据条数是否能对上

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐