Mysql课后项目-->InnoAI SQL 助手

项目概述

InnoAI SQL助手基于Python与openEuler环境,融合MySQL8.0运维技术与大模型接口,面向电商订单场景实现自然语言生成SQL、自动查询与SQL性能调优。系统分层开发,提供网页可视化、命令行双操作入口,依托统一配置文件管理敏感信息,底层数据库存储订单数据,对接大模型提供AI解析能力。使用者无需掌握SQL,输入自然语言即可自动完成数据查询、报表输出与索引优化,简化数据库重复运维工作;项目轻量化部署,单人分三阶段完成开发,适配企业轻量化数据运维场景。

1.项目环境搭建

(1)在虚拟机上部署 openEuler 服务器

由于MySQL开课的第一节课老师就已经让我们完成部署,此过程就不在过多的讲解
纯享版教程链接-->使用 VMWare 安装 openEuler-24.03 虚拟机_哔哩哔哩_bilibili

(2)优化服务器
  • 关闭selinux和防火墙
1.sed -i '7s/enforcing/disabled/'  /etc/selinux/config  # 关闭selinux
2. systemctl  disable --now  firewalld  # 关闭防火墙
3. systemctl  status  firewalld  # 查看防火墙状态

防火墙关闭后的状态

image.png

selinux关闭后的状态

image.png
  • 修改主机名
1. hostnamectl  set-hostname  server
2.bash   # 这里也可以用reboot
  • 更换时间同步服务器
1.vim  /etc/chrony.conf   
# 这里要用#号注释掉它原本的时间服务器,如下面/**/里的内容
# 解释一下,这里之所以要换服务器是因为openeuler的服务器在国内的延迟高、连通性差,会导致时间不同步,这会对后面使用yum下载东西的时候报错
/*
 Use public servers from the pool.ntp.org project.
 Please consider joining the pool (https://www.pool.ntp.org/join.html).
*/
2.server ntp.aliyun.com iburst
3. systemctl restart chronyd # 重启服务器
4.chronyc sources # 验证改动后的时间服务,时间是否同步
#若嫌麻烦可以直接手动同步日期,操作如下
date -s "年-月-日 时:分:秒"
  • 下载所需软件及依赖
dnf install -y gcc gcc-c++ make cmake zlib-devel bzip2-devel openssl-devel ncurses-devel 
sqlite-devel readline-devel libffi-devel tk-devel wget tar vim tree net-tools openssh-server
(3) 源码编译安装Python3.11.9
  • 在Python的官网可以找到Python的源码包(如下图),然后下载


    image.png
  • 下载完毕后使用XFTP将源码包上传到/usr/local/src路径下(具体操作如下)

    1.先在远程连接了部署过openeuler虚拟机的Xshell上,将目录路径切换到源码包的存放路径/usr/local/src


    image.png

    2.打开XFTP将Windows上的文件拉到/usr/local/src目录


    image.png

    image.png
  • 解压压缩包

    image.png

    image.png
  • 检测系统环境生成编译说明书(makefile)

    image.png

    image.png

    --enable-shared ->编译时生成Python动态共享库

  • 编译与安装

    image.png

    -j ->用于开启多核并行编译;
    nproc ->自动获取服务器CPU的核心数(这里可以直接写成你Linux核心数)

  • 配置动态链接库,解决libpython缺失报错

    image.png
  • 建立全局软链接

    image.png

    image.png

    建立完链接后要重启才生效(bash/reboot)
    image.png

    解释:由于Linux自带python(如上图的python 3.9.9),这时并没有使用到刚才下载的python-3.11.9版本,所以为了再不覆盖自带的python的同时调用我们自己下的python,采用了建立软链接的方式进行调用;在建立完连接之后,之所以能调用我们的那个python版本,是因为Linux执行命令规则:按照 path 目录顺序查找绝大多数系统默认path顺序:/usr/local/bin 排在 /usr/bin 前面

  • 检测安全校验SSL模块是否被识别

    image.png
  • 配置pip仓库为阿里镜像站,提高下载速度
    这里在前面上课的时候我已经相应的配置,所以这儿只讲步骤

    1.cd #切换到根目录
    2.mkdir .pip
    3. vim  ~/.pip/pip.conf
    

    ~/.pip/pip.conf中编辑的内容:

    image.png
  • 升级pip3 and python的依赖

    image.png

    image.png
(4)部署MySQL 8.0.45并创建测试的库与表
  • 部署MySQL 8.0.45
    这一步在前面上课的时候就已经部署,我就不过多的讲解
    MySQL 8.0.45的安装文档:(https://www.jianshu.com/p/db7b6988f252?v=1785510127849)
  • 创建并使用数据库
    image.png
  • 创建表并插入数据
    image.png

    image.png

    image.png
  • 获取API Key
    1.访问腾讯云官网
    2.找到大模型里面的TokenHub模型
    3.找到《免费领取,100万token》的那一栏,点击立即前往
    4.在模型广场旁边,地域选择离自己最近的"广州"
    5.在左侧找到 API key管理,进入后点击新建API


    image.png

2.脚本开发阶段

  • 新建目录

    image.png

    image.png
  • 编写环境变量脚本及其权限修改

    image.png

    image.png

    说明:
    1.MYSQL_PASSEORD写自己的
    2.LLM_API_KEY去复制刚才自己申请的
    3.LLM_BASE_URL 和LLM_MODEL_NAME的获取位置
    在刚才 “API key管理”的上方找到模型广场-->找到全部模型-->找到DeepSeek-V4-Pro点击进入-->找到右上角的API调用点击进入-->找到调用服务选择python,base_url和model后面的内容就是你所需要的

    权限修改

    image.png

    解释:
    由于.env文件里存放密码等一些重要的内容,这里面的东西只能自己读写,别人不能有任何权限,所以这里把权限改成600

  • 编写数据库连接脚本

    image.png

    image.png

    image.png

    image.png

    image.png

    image.png

    image.png

    image.png

    image.png
  • 编写sql转换脚本

    image.png

    image.png

    image.png

    image.png

    image.png

    image.png

    image.png

    image.png

    image.png
  • 编写程序入口脚本

    image.png

    image.png
# 加载.env文件里所有数据库、大模型配置
load_dotenv()

# 全局日志配置,替代print,记录运行时间、日志级别、报错信息,方便排障
logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")
logger = logging.getLogger(__name__)


def check_config() -> None:
  """
  程序启动前置配置校验函数
  作用:提前检测.env必填参数是否存在,避免运行中途缺参数崩溃
  """
  # 大模型必填参数列表
  required_llm = ["LLM_API_KEY", "LLM_BASE_URL", "LLM_MODEL_NAME"]
  missing = [k for k in required_llm if not os.getenv(k)]
  if missing:
      raise ValueError(f"配置缺失:请在 .env 文件中填写 {', '.join(missing)}")

  # 数据库必填参数列表
  required_db = ["MYSQL_HOST", "MYSQL_USER", "MYSQL_DB"]
  missing_db = [k for k in required_db if not os.getenv(k)]
  if missing_db:
      raise ValueError(f"数据库配置缺失:请检查 {', '.join(missing_db)}")

def get_llm() -> ChatOpenAI:
    """
    初始化大模型客户端
    适配腾讯云TokenHub等全部兼容OpenAI接口规范的MaaS平台
    返回:可直接调用的大模型实例
    """
    # 从环境变量读取大模型连接信息
    api_key = os.getenv("LLM_API_KEY")
    base_url = os.getenv("LLM_BASE_URL")
    model_name = os.getenv("LLM_MODEL_NAME")
    # 温度不存在则默认0.1,数值越低输出越严谨稳定
    temperature = float(os.getenv("LLM_TEMPERATURE", 0.1))

    return ChatOpenAI(
        api_key=api_key,
        base_url=base_url,
        model=model_name,
        temperature=temperature
    )

def clean_sql_spacing(sql: str) -> str:
    """
    SQL标准化清洗工具函数(兜底修复各大模型输出格式)
    解决:中文空格别名、中文标点、特殊空白、关键字连写等语法报错问题
    入参:大模型原始SQL字符串
    返回:清洗后可直接执行的标准英文SQL
    """
    if not sql:
        return ""

    # 1. 统一替换各类中文全角空格、换行、制表符为普通半角空格
    special_spaces = [
        '\xa0', '\u200b', '\u200c', '\u200d', '\u200e', '\u200f',
        '\u3000', '\t', '\n', '\r'
    ]
    for sp in special_spaces:
        sql = sql.replace(sp, ' ')

    # 2. 删除不可见控制字符,防止解析异常
    sql = re.sub(r'[\x00-\x1f\x7f]', '', sql)

    # 3. 中文标点批量替换为英文标点(解决Qwen等模型输出中文逗号报错)
    sql = sql.replace(',', ',').replace(';', ';').replace('(', '(').replace(')', ')')

    # 4. 多个连续空格合并为单个,去除首尾多余空格
    sql = re.sub(r'\s+', ' ', sql).strip()

 # 5. 精准处理AS别名内部空格,只删别名里空格,保留AS与别名之间分隔空格
    def _clean_alias_space(match):
        prefix = match.group(1)  # 捕获AS关键字
        alias = match.group(2)   # 捕获后面全部别名文本
        alias_clean = re.sub(r'\s+', '', alias)
        return f"{prefix} {alias_clean}"

    # 匹配AS后别名,截止逗号、FROM、WHERE等关键字前停止匹配
    sql = re.sub(
        r'\b(AS)\s+(.+?)(?=\s*,\s*|\s+FROM\b|\s+WHERE\b|\s+ORDER\b|\s+GROUP\b|\s+LIMIT\b|\s*;)',
        _clean_alias_space,
        sql,
        flags=re.IGNORECASE
    )

    # 6. 自动给连写的关键字补空格(字段/中文+关键字粘连自动拆分)
    keywords_upper = [
        "SELECT", "FROM", "WHERE", "ORDER BY", "GROUP BY",
        "AND", "OR", "LIMIT", "DESC", "ASC", "AS",
        "INNER JOIN", "LEFT JOIN", "RIGHT JOIN", "ON",
        "INSERT INTO", "UPDATE", "SET", "DELETE FROM",
        "VALUES", "LIKE", "IN", "BETWEEN", "IS NULL",
        "COUNT", "SUM", "AVG", "MAX", "MIN", "OVER"
    ]
    for kw in keywords_upper:
        # 字母下划线+关键字粘连拆分,补充第三个参数sql
        pattern = r'([a-z_])(' + re.escape(kw) + r')'
        sql = re.sub(pattern, r'\1 \2', sql)
        # 中文文字+关键字粘连拆分,补充第三个参数sql
        pattern_cn = r'([\u4e00-\u9fa5])(' + re.escape(kw) + r')'
        sql = re.sub(pattern_cn, r'\1 \2', sql)

    # 7. 统一所有SQL关键字大写,格式标准化
    keywords_lower = [kw.lower() for kw in keywords_upper]
    for kw in keywords_lower:
        sql = re.sub(
            r'\b' + re.escape(kw) + r'\b',
            kw.upper(),
            sql,
            flags=re.IGNORECASE
        )

    # 最终再清理一遍多余空格
    sql = re.sub(r'\s+', ' ', sql).strip()
    return sql

def nl2sql_query(user_input: str) -> dict:
    """
    核心业务1:自然语言转SQL、执行查询、AI生成业务总结
    对外统一标准返回字典,终端/网页程序均可直接调用,无重复代码
    入参:用户自然语言查询需求
    返回:包含执行状态、SQL、字段、数据、AI总结、模型原始输出
    """
    # 初始化大模型、数据库客户端
    llm = get_llm()
    db = Mysql80Client()

    try:
        logger.info("正在生成SQL语句...")
        # 1. 加载NL2SQL提示词,填充用户需求传给大模型
        prompt = UnifiedPrompt.NL_TO_SQL_PROMPT.format(user_input=user_input)
        response = llm.invoke(prompt)
        raw_content = response.content.strip()

        # 2. 从模型返回文本提取纯净SQL,提取失败直接抛异常
        extracted_sql = prompt_helper.extract_sql(raw_content)
        if not extracted_sql:
            raise Exception("大模型未返回有效SQL,请重新描述需求")

        # 3. 清洗SQL修复各类格式问题
        clean_sql = clean_sql_spacing(extracted_sql)
        logger.info(f"生成SQL:{clean_sql}")

        # 4. 数据库执行查询,拿到表头与数据
        columns, rows = db.execute_query(clean_sql)

        # 5. 如果有数据,调用大模型生成业务解读总结
        summary = ""
        if rows:
            logger.info("正在生成数据总结...")
            summary_prompt = f"""
            以下是真实的SQL查询结果,请作为电商数据分析师给出简练的业务总结。
            SQL语句:{clean_sql}
            查询数据:{str(rows)}
            重点说明数据反映的业务含义,如有异常值请指出。
            """
            summary_resp = llm.invoke(summary_prompt)
            summary = summary_resp.content.strip()

        # 成功结果返回
        return {
            "success": True,
            "sql": clean_sql,
            "columns": columns,
            "rows": rows,
            "summary": summary,
            "raw_llm": raw_content
        }

    except Exception as e:
        # 捕获全流程所有异常,记录日志并返回错误信息
        logger.error(f"查询处理失败:{str(e)}")
        return {
            "success": False,
            "error": str(e),
            "raw_llm": raw_content if 'raw_content' in dir() else ""
        }
    finally:
        # 无论成功失败,都关闭数据库连接释放资源
        db.close()

def sql_tune_analyze(raw_sql: str) -> dict:
    """
    核心业务2:SQL性能调优分析
    流程:清洗SQL → 获取EXPLAIN执行计划 → AI分析给出优化方案
    入参:用户输入待优化SQL
    返回:执行状态、清洗后SQL、执行计划字段/内容、调优建议
    """
    llm = get_llm()
    db = Mysql80Client()

    try:
        # 先标准化清洗SQL
        clean_sql = clean_sql_spacing(raw_sql)
        logger.info("正在获取执行计划...")

        # 调用数据库封装方法获取EXPLAIN执行计划
        columns, plan_rows = db.get_explain_plan(clean_sql)

        # 填充调优提示词,传入SQL和执行计划让AI分析瓶颈
        logger.info("正在分析性能瓶颈...")
        prompt = UnifiedPrompt.SQL_TUNE_PROMPT.format(
            sql_input=clean_sql,
            explain_data=str(plan_rows)
        )
        response = llm.invoke(prompt)

        return {
            "success": True,
            "sql": clean_sql,
            "plan_columns": columns,
            "plan_rows": plan_rows,
            "suggestion": response.content.strip()
        }

    except Exception as e:
        logger.error(f"调优分析失败:{str(e)}")
        return {
            "success": False,
            "error": str(e)
        }
    finally:
        # 操作结束关闭数据库连接
        db.close()

def main_cli():
    """
    终端交互入口主函数
    提供循环菜单,支持用户选择查询/调优/退出,纯终端操作
    """
    # 程序启动先校验全部配置,失败直接退出菜单
    try:
        check_config()
    except ValueError as e:
        print(f"❌ {e}")
        return

    # 循环交互,不退出可持续多次使用
    while True:
        print("\n=============== InnoAI SQL 助手 ===============")
        print("1. 自然语言生成SQL,自动查询并AI总结数据")
        print("2. 输入SQL语句,AI分析执行计划并给出调优方案")
        print("0. 退出程序")

        choice = input("请输入功能序号: ").strip()

        # 功能1:自然语言查数据
        if choice == '1':
            query = input("请输入你的数据查询需求: ").strip()
            if not query:
                print("⚠️ 请输入有效需求")
                continue

            result = nl2sql_query(query)
            # 处理失败场景,打印错误与模型原始输出
            if not result["success"]:
                print(f"\n❌ 处理失败:{result['error']}")
                if result.get("raw_llm"):
                    print(f"大模型原始回复:\n{result['raw_llm']}")
                continue

            # 成功:打印SQL、格式化表格展示数据、输出业务总结
            print(f"\n✅ 生成SQL:")
            print(result["sql"])
            if result["rows"]:
                print(f"\n📊 查询结果(共 {len(result['rows'])} 条):")
                print(tabulate(result["rows"], headers="keys", tablefmt="pretty"))
                if result["summary"]:
                    print(f"\n💡 业务总结:\n{result['summary']}")
            else:
                print("\n⚠️ 未查询到匹配数据")

        # 功能2:SQL性能调优
        elif choice == '2':
            sql_input = input("\n请输入需要分析的 SQL 语句: ").strip()
            if not sql_input:
                print("⚠️ 请输入有效SQL")
                continue

            result = sql_tune_analyze(sql_input)
            if not result["success"]:
                print(f"\n❌ 分析失败:{result['error']}")
                continue

            # 打印执行计划表格和AI优化建议
            print(f"\n📊 执行计划详情:")
            print(tabulate(result["plan_rows"], headers="keys", tablefmt="pretty"))
            print(f"\n📈 调优建议:\n{result['suggestion']}")

        # 0 退出循环,结束程序
        elif choice == '0':
            print("程序已安全退出。")
            break
        # 无效数字输入提示
        else:
            print("无效输入,请重试。")

        print("\n" + "-" * 40)


# 程序入口:直接运行main.py则启动终端菜单
if __name__ == "__main__":
    main_cli()
  • 编写web可视化页面
    这里我们用到的是Streamlit-->一款开源、纯 Python Web 开发库;不用写 HTML/CSS/JS,只用 Python 就能快速做交互式网页,专门面向数据分析师、后端、AI 工程师,把本地脚本一键变成可视化 Web 面板
    1.安装 Python 依赖
    image.png

2.检查安装的依赖是否正常


image.png

3.用 Streamlit编写可视化入口脚本

image.png

image.png
# ====================== 全局CSS样式定制:优化字体、间距、按钮、代码块、表格展示 ======================
# 使用markdown注入前端样式,统一页面视觉效果,方便演示观看
st.markdown("""
<style>
/* 全局文字基础样式:统一字体、字号、行间距,适配Windows/Mac中文显示 */
html, body, [class*="css"]  {
    font-size: 15px;
    line-height: 1.6;
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Microsoft YaHei", sans-serif;
}

/* 页面主体容器:左右留白收窄,太宽的数据表格阅读疲劳 */
.block-container {
    padding-top: 2.5rem;
    padding-bottom: 3rem;
    max-width: 1100px;
    margin: 0 auto;
}

/* 各级标题字号、粗细、边距统一优化 */
h1 {
    font-size: 2rem !important;
    font-weight: 600;
    margin-bottom: 1.8rem;
    letter-spacing: 0.5px;
}
h2, h3 {
    font-weight: 600;
    margin-top: 1.5rem;
    margin-bottom: 1rem;
}
h3 {
    font-size: 1.25rem !important;
}

/* 文本输入框标签样式美化 */
.stTextArea label p {
    font-size: 15px;
    font-weight: 500;
    color: #1f2937;
    margin-bottom: 0.5rem;
}
/* 输入框内部样式:字号、圆角、内边距 */
textarea {
    font-size: 15px !important;
    line-height: 1.6 !important;
    border-radius: 8px !important;
    padding: 12px 14px !important;
}

/* 全局操作按钮统一尺寸、圆角、内边距,视觉统一 */
.stButton > button {
    font-size: 15px !important;
    font-weight: 500;
    padding: 0.65rem 2.2rem !important;
    border-radius: 8px !important;
    min-width: 160px;
}

/* 左侧侧边栏样式调整 */
section[data-testid="stSidebar"] {
    font-size: 14.5px;
}
/* 侧边大标题禁止自动换行 */
section[data-testid="stSidebar"] h1 {
    font-size: 1.5rem !important;
    white-space: nowrap;
    margin-bottom: 1.2rem;
}
/* 侧边单选按钮间距放大 */
section[data-testid="stSidebar"] .stRadio > div {
    gap: 0.8rem;
}
/* 提示警告框字号统一 */
.stAlert {
    font-size: 14.5px;
    border-radius: 8px !important;
}
/* ========== 重点修复:代码块复制按钮失效问题 ========== */
.stCodeBlock {
    position: relative !important;
    border-radius: 8px !important;
}
/* 强制显示复制按钮,提高层级防止被遮挡 */
.stCodeBlock button {
    opacity: 1 !important;
    visibility: visible !important;
    pointer-events: auto !important;
    z-index: 999 !important;
    width: 36px;
    height: 36px;
    top: 10px;
    right: 10px;
    border-radius: 6px;
    background: #f3f4f6 !important;
    color: #374151 !important;
    border: 1px solid #e5e7eb !important;
}
/* 按钮悬浮变色提升交互感 */
.stCodeBlock button:hover {
    background: #e5e7eb !important;
}

/* SQL代码等宽字体优化,提升代码可读性 */
.stCodeBlock code, .stCodeBlock pre {
    font-size: 14.5px !important;
    line-height: 1.7 !important;
    font-family: "JetBrains Mono", Consolas, Monaco, monospace;
}

/* 数据表格单元格内边距放大,避免文字拥挤 */
.stDataFrame {
    font-size: 14.5px;
    border-radius: 8px;
    overflow: hidden;
}
.stDataFrame [data-testid="table"] td {
    padding: 10px 12px;
}
</style>
""", unsafe_allow_html=True)

# 全局一次性配置校验,会话缓存避免重复校验
# st.session_state:streamlit会话全局存储,页面刷新前一直生效
if "config_checked" not in st.session_state:
    try:
        # 调用main.py的配置校验函数,检测.env文件必填参数
        check_config()
        # 标记已校验,下次页面刷新不再重复执行
        st.session_state.config_checked = True
    except ValueError as e:
        # 配置缺失直接弹窗报错,终止页面加载
        st.error(f"配置错误:{e}")
        st.stop()
# ========== 左侧侧边栏区域:系统标题、当前模型展示、页面切换导航 ==========
with st.sidebar:
    st.title("🚀 InnoAI SQL 助手")
    # 读取环境变量,展示当前正在使用的大模型名称
    st.info(f"当前模型:{os.getenv('LLM_MODEL_NAME', '未知')}")
    # 单选框切换两大功能页面
    page = st.radio("功能导航", ["🔍 数据查询与总结", "⚙️ SQL 性能调优"])

# ====================== 页面1:自然语言转SQL查询页面 ======================
if page == "🔍 数据查询与总结":
    st.header("💬 自然语言转 SQL 查询")
    # 多行文本输入框,接收用户中文业务需求
    user_input = st.text_area("请输入你的业务查询需求:", height=150)

    # 点击提交按钮触发查询逻辑
    if st.button("🚀 生成并执行", type="primary"):
        input_trim = user_input.strip()
        # 校验1:输入为空拦截
        if not input_trim:
            st.warning("请输入有效的业务查询需求后再提交")
        
        # 校验2:禁止直接粘贴SQL,区分两个页面的使用场景
        elif re.match(r'(?i)^\s*SELECT\s+', input_trim):
            st.warning("此处请输入自然语言描述的查询需求(例如:查询用户 1001 的所有订单),请勿直接粘贴 SQL 语句。")
        
        # 输入校验全部通过,执行AI查询逻辑
        else:
            # 加载动画提示用户等待
            with st.spinner("AI 正在生成 SQL 并查询数据..."):
                # 调用main封装好的核心业务方法
                result = nl2sql_query(user_input)

                # 分支1:业务执行失败,展示错误信息
                if not result["success"]:
                    st.error(f"处理失败:{result['error']}")
                    # 折叠面板展示大模型原始返回内容,方便排错
                    if result.get("raw_llm"):
                        with st.expander("查看大模型原始回复"):
                            st.code(result["raw_llm"])
                # 分支2:执行成功,分层展示结果
                else:
                    st.success("SQL 生成并执行成功")
                    # 高亮展示生成后的标准SQL语句
                    st.code(result["sql"], language="sql")

                    # 存在查询数据则渲染表格
                    if result["rows"]:
                        st.dataframe(result["rows"], use_container_width=True)
                        # 存在AI业务总结则展示解读文本
                        if result["summary"]:
                            st.markdown("### 💡 业务总结")
                            st.info(result["summary"])
                    # 无匹配订单提示
                    else:
                        st.info("未查询到匹配的数据")
# ====================== 页面2:SQL性能调优分析页面 ======================
else:
    st.header("🔧 SQL 性能调优分析")
    # 输入框接收用户待优化SELECT语句
    raw_sql = st.text_area("请输入待分析的 SQL 语句:", height=200)

    # 点击分析按钮执行调优流程
    if st.button("📊 开始分析", type="primary"):
        input_trim = raw_sql.strip()
        # 校验1:空输入拦截
        if not input_trim:
            st.warning("请输入有效的 SQL 语句后再提交")
        
        # 校验2:必须是SELECT语句,禁止其他类型SQL
        elif not re.match(r'(?i)^\s*SELECT\s+', input_trim):
            st.warning("此处请输入待分析的 SELECT SQL 语句,请勿输入自然语言描述。如需自然语言转 SQL,请切换到「数据查询与总结」页面。")
        
        # 校验通过,执行调优分析
        else:
            with st.spinner("正在获取执行计划并分析..."):
                # 调用main封装的调优函数
                result = sql_tune_analyze(raw_sql)

                # 分析失败展示错误
                if not result["success"]:
                    st.error(f"分析失败:{result['error']}")
                # 分析成功,展示执行计划表格+AI优化建议
                else:
                    st.success("执行计划获取成功")
                    st.dataframe(result["plan_rows"], use_container_width=True)

                    st.markdown("### 💡 调优建议")
                    st.markdown(result["suggestion"])

4.将Streamlit的可视化界面,当成Linux服务来对待

image.png

image.png

5.重启服务

image.png

image.png

3.测试

  • 命令行终端模式测试
image.png

image.png

image.png
  • Web 可视化模式测试
    1.查看ip


    image.png

    2.浏览器访问:192.168.248.145:8501


    image.png

    image.png
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容