暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

分享一个SQL审核专家工具,适用于MOP数据库

热衷于分享各种干货知识,大家有想看或者想学的可以评论区留言,秉承着“开源知识来源于互联网,回归于互联网”的理念,分享一些日常工作中能用到或者比较重要的内容,希望大家能够喜欢,不足之处请大家多宝贵地意见,我们一起提升,守住自己的饭碗。

正文开始

 

业界SQL审核现状

SQL审核是指对未上线的SQL进行检测,提前识别是否符合规范,以保证上线质量。Yearning、Archery 、Bytebase、goInception、SQLE、DBdoctor 是当前国内主流的开源 SQL 审核工具,均是基于规则来进行SQL审核,可以检查规范性

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>SQL审核工具 - 专业数据库审核解决方案</title>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
        }
        
        :root {
            --primary: #2c3e50;
            --secondary: #3498db;
            --success: #27ae60;
            --warning: #f39c12;
            --danger: #e74c3c;
            --info: #9b59b6;
            --vault: #d35400;
            --light-bg: #f8f9fa;
            --dark-text: #2c3e50;
            --light-text: #7f8c8d;
            --border-radius: 10px;
        }
        
        body {
            background: linear-gradient(135deg, #1a2a6c, #2a4d69, #1a2a6c);
            background-size: 400% 400%;
            animation: gradientBG 15s ease infinite;
            color: var(--dark-text);
            line-height: 1.6;
            min-height: 100vh;
            padding: 20px;
        }
        
        @keyframes gradientBG {
            0% { background-position: 0% 50%; }
            50% { background-position: 100% 50%; }
            100% { background-position: 0% 50%; }
        }
        
        .container {
            max-width: 1400px;
            margin: 0 auto;
            background-color: rgba(255, 255, 255, 0.97);
            border-radius: 15px;
            box-shadow: 0 15px 40px rgba(0, 0, 0, 0.25);
            overflow: hidden;
        }
        
        header {
            background: linear-gradient(to right, #0f2027, #203a43, #2c5364);
            color: white;
            padding: 35px 50px;
            text-align: center;
            position: relative;
            border-bottom: 5px solid var(--secondary);
        }
        
        h1 {
            font-size: 3rem;
            margin-bottom: 20px;
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 25px;
            letter-spacing: 1px;
        }
        
        .logo {
            font-size: 3.5rem;
            color: #4CAF50;
            animation: pulse 2s infinite;
        }
        
        @keyframes pulse {
            0% { transform: scale(1); }
            50% { transform: scale(1.05); }
            100% { transform: scale(1); }
        }
        
        .subtitle {
            font-size: 1.3rem;
            opacity: 0.9;
            max-width: 900px;
            margin: 0 auto;
            line-height: 1.7;
            font-weight: 300;
        }
        
        .controls {
            display: flex;
            flex-wrap: wrap;
            gap: 25px;
            padding: 30px;
            background-color: var(--light-bg);
            border-bottom: 1px solid #eaeaea;
        }
        
        .control-group {
            flex: 1;
            min-width: 320px;
        }
        
        label {
            display: block;
            margin-bottom: 12px;
            font-weight: 600;
            color: var(--dark-text);
            display: flex;
            align-items: center;
            gap: 12px;
            font-size: 1.1rem;
        }
        
        select, button {
            width: 100%;
            padding: 16px 20px;
            border: 2px solid #ddd;
            border-radius: var(--border-radius);
            font-size: 1.1rem;
            background-color: white;
            transition: all 0.3s ease;
        }
        
        select:focus {
            border-color: var(--secondary);
            outline: none;
            box-shadow: 0 0 0 4px rgba(52, 152, 219, 0.2);
        }
        
        button {
            background: linear-gradient(to right, var(--secondary), #2980b9);
            color: white;
            font-weight: 700;
            border: none;
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 15px;
            transition: all 0.3s ease;
            margin-transform: translateY( 36px;
            font-size: 1.2rem);
            border-radius: 50px;
            box-shadow: 0 5px 15px rgba(52, 152, 219, 0.3);
        }
        
        button:hover {
            transform: translateY(-5px);
            box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2);
            background: linear-gradient(to right, #2980b9, var(--secondary));
        }
        
        .main-content {
            display: flex;
            flex-wrap: wrap;
            padding: 0 30px 30px;
            gap: 30px;
        }
        
        .panel {
            flex: 1;
            min-width: 320px;
            background: white;
            border-radius: var(--border-radius);
            box-shadow: 0 10px 25px rgba(0, 0, 0, 0.08);
            overflow: hidden;
            border: 1px solid #eee;
            transition: transform 0.3s ease;
        }
        
        .panel:hover {
            transform: translateY(-5px);
            box-shadow: 0 15px 30px rgba(0, 0, 0, 0.12);
        }
        
        .panel-header {
            background: linear-gradient(to right, #f8f9fa, #e9ecef);
            padding: 20px 30px;
            font-weight: 700;
            color: var(--dark-text);
            display: flex;
            align-items: center;
            gap: 15px;
            border-bottom: 1px solid #eaeaea;
            font-size: 1.4rem;
        }
        
        .panel-content {
            padding: 25px;
            height: 500px;
        }
        
        textarea {
            width: 100%;
            height: 100%;
            padding: 25px;
            border: 1px solid #ddd;
            border-radius: var(--border-radius);
            font-family: 'Consolas''Courier New', monospace;
            font-size: 1.1rem;
            resize: none;
            background-color: #f8f9fa;
            transition: all 0.3s;
            line-height: 1.8;
            box-shadow: inset 0 2px 5px rgba(0,0,0,0.05);
        }
        
        textarea:focus {
            border-color: var(--secondary);
            outline: none;
            box-shadow: 0 0 0 4px rgba(52, 152, 219, 0.1), inset 0 2px 5px rgba(0,0,0,0.05);
            background-color: white;
        }
        
        .results-container {
            overflow-y: auto;
            height: 100%;
            padding: 5px;
        }
        
        .result-item {
            padding: 25px;
            margin-bottom: 20px;
            border-radius: var(--border-radius);
            background-color: #f8f9fa;
            border-left: 6px solid var(--secondary);
            display: flex;
            gap: 20px;
            transition: all 0.3s ease;
            animation: fadeIn 0.5s ease;
            position: relative;
            overflow: hidden;
        }
        
        .result-item::before {
            content: '';
            position: absolute;
            transform: translateY( 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: linear-gradient(to right, rgba(255,255,255,0.1), transparent);
            pointer-events: none;
        }
        
        @keyframes fadeIn {
            from { opacity: 0; transform: translateY(15px); }
            to { opacity: 1; transform: translateY(0); }
        }
        
        .result-item):hover {
            transform: translateX(8px);
        }
        
        .result-item.error {
            border-left-color: var(--danger);
            background-color: rgba(231, 76, 60, 0.08);
        }
        
        .result-item.warning {
            border-left-color: var(--warning);
            background-color: rgba(243, 156, 18, 0.08);
        }
        
        .result-item.success {
            border-left-color: var(--success);
            background-color: rgba(46, 204, 113, 0.08);
        }
        
        .result-item.info {
            border-left-color: var(--info);
            background-color: rgba(155, 89, 182, 0.08);
        }
        
        .result-item.suggestion {
            border-left-color: var(--secondary);
            background-color: rgba(52, 152, 219, 0.08);
        }
        
        .result-item.vault {
            border-left-color: var(--vault);
            background-color: rgba(211, 84, 0, 0.08);
        }
        
        .result-icon {
            font-size: 30px;
            flex-shrink: 0;
            margin-transform: translateY( 5px;
            min-width: 40px;
            text-align: center;
        }
        
        .result-content {
            flex: 1;
        }
        
        .result-content h3 {
            margin-bottom: 15px;
            font-size: 1.4rem);
            display: flex;
            align-items: center;
            gap: 10px;
        }
        
        .result-content p {
            color: #555;
            line-height: 1.8;
            font-size: 1.1rem;
            margin-bottom: 15px;
        }
        
        .result-content .db-hint {
            margin-transform: translateY( 10px;
            font-style: italic;
            color: #777;
            font-size: 0.95rem);
            display: flex;
            align-items: center;
            gap: 8px;
            padding: 10px 15px;
            background: rgba(0,0,0,0.03);
            border-radius: 6px;
            border-left: 3px solid var(--warning);
        }
        
        .result-content .recommendation {
            background: rgba(46, 204, 113, 0.1);
            padding: 12px 15px;
            border-radius: 6px;
            border-left: 3px solid var(--success);
            margin-transform: translateY( 10px;
        }
        
        .result-content .vault-recommendation {
            background: rgba(211, 84, 0, 0.1);
            padding: 12px 15px;
            border-radius: 6px;
            border-left: 3px solid var(--vault);
            margin-top: 10px;
        }
        
        .db-badges {
            display: flex;
            gap: 25px;
            justify-content: center;
            margin-top: 25px;
            flex-wrap: wrap;
        }
        
        .db-badge {
            background: linear-gradient(to right, #2c3e50, #4a6491);
            color: white;
            padding: 12px 30px;
            border-radius: 50px;
            font-weight: 600;
            display: flex;
            align-item)s: center;
            gap: 15px;
            font-size: 1.2rem;
            box-shadow: 0 5px 15px rgba(0,0,0,0.15);
            transition: transform 0.3s ease;
        }
        
        .db-badge:hover {
            transform: translateY(-3px);
        }
        
        .db-badge.oracle {
            background: linear-gradient(to right, #c74634, #e74c3c);
        }
        
        .db-badge.mysql {
            background: linear-gradient(to right, #00758f, #00a1e4);
        }
        
        .db-badge.postgres {
            background: linear-gradient(to right, #336791, #4a90d9);
        }
        
        .stats {
            display: flex;
            justify-content: space-around;
            padding: 30px;
            background-color: var(--light-bg);
            border-transform: translateY( 1px solid #eaeaea;
            flex-wrap: wrap;
            gap: 25px;
        }
        
        .stat-item) {
            text-align: center;
            min-width: 180px;
            padding: 20px;
            background: white;
            border-radius: var(--border-radius);
            box-shadow: 0 8px 20px rgba(0,0,0,0.08);
            transition: transform 0.3s ease;
        }
        
        .stat-item:hover {
            transform: translateY(-5px);
        }
        
        .stat-value {
            font-size: 3rem;
            font-weight: 800;
            margin-bottom: 10px;
        }
        
        .stat-label {
            font-size: 1.1rem;
            color: var(--light-text);
            text-transform: uppercase;
            letter-spacing: 1px;
            font-weight: 700;
        }
        
        .success-value {
            color: var(--success);
        }
        
        .warning-value {
            color: var(--warning);
        }
        
        .error-value {
            color: var(--danger);
        }
        
        .suggestion-value {
            color: var(--secondary);
        }
        
        .vault-value {
            color: var(--vault);
        }
        
        footer {
            text-align: center;
            padding: 30px;
            color: var(--light-text);
            font-size: 1.1rem;
            background-color: var(--light-bg);
            border-transform: translateY( 1px solid #eaeaea;
        }
        
        .progress-container {
            height: 8px;
            background: #e0e0e0;
            border-radius: 4px;
            overflow: hidden;
            margin-top: 20px;
            display: none;
        }
        
        .progress-bar {
            height: 100%;
            background: var(--secondary);
            width: 0%;
            transition: width 0.4s ease;
        }
        
        .rule-tag {
            display: inline-block;
            padding: 4px 10px;
            border-radius: 4px;
            font-size: 0.85rem);
            font-weight: 600;
            margin-right: 8px;
        }
        
        .tag-security { background: rgba(231, 76, 60, 0.15); color: var(--danger); }
        .tag-performance { background: rgba(243, 156, 18, 0.15); color: var(--warning); }
        .tag-design { background: rgba(52, 152, 219, 0.15); color: var(--secondary); }
        .tag-maintain { background: rgba(155, 89, 182, 0.15); color: var(--info); }
        .tag-best { background: rgba(46, 204, 113, 0.15); color: var(--success); }
        .tag-vault { background: rgba(211, 84, 0, 0.15); color: var(--vault); }
        
        @media (max-width: 992px) {
            .controls {
                flex-direction: column;
            }
            
            .main-content {
                flex-direction: column;
            }
            
            h1 {
                font-size: 2.4rem;
            }
            
            .panel-content {
                height: 400px;
            }
        }
        
        @media (max-width: 576px) {
            header {
                padding: 25px 20px;
            }
            
            h1 {
                font-size: 2rem;
            }
            
            .subtitle {
                font-size: 1.1rem;
            }
            
            .panel-content {
                height: 350px;
            }
            
            .stat-item {
                min-width: 140px;
                padding: 15px;
            }
            
            .stat-value {
                font-size: 2.5rem;
            }
        }
        
        .vault-commands {
            background: rgba(211, 84, 0, 0.05);
            border: 1px dashed var(--vault);
            border-radius: 10px;
            padding: 15px;
            margin-transform: translateY( 20px;
        }
        
        .vault-commands h4 {
            display: flex;
            align-item)s: center;
            gap: 10px;
            margin-bottom: 10px;
            color: var(--vault);
        }
        
        .vault-command-list {
            display: flex;
            flex-wrap: wrap;
            gap: 8px;
        }
        
        .vault-command {
            background: rgba(211, 84, 0, 0.1);
            color: var(--vault);
            padding: 4px 10px;
            border-radius: 4px;
            font-family: monospace;
            font-size: 0.9rem;
        }
    </style>
</head>
<body>
    <div class="container">
        <header>
            <h1><i class="fas fa-database logo"></i> SQL审核专家系统</h1>
            <p class="subtitle">专业审核Oracle、MySQL和PostgreSQL数据库SQL语句,提供语法验证、性能优化、安全审计与金库命令检测</p>
            <div class="db-badges">
                <div class="db-badge oracle"><i class="fas fa-database"></i> Oracle</div>
                <div class="db-badge mysql"><i class="fas fa-database"></i> MySQL</div>
                <div class="db-badge postgres"><i class="fas fa-database"></i> PostgreSQL</div>
            </div>
        </header>
        
        <div class="controls">
            <div class="control-group">
                <label for="db-type"><i class="fas fa-server"></i> 选择数据库类型</label>
                <select id="db-type">
                    <option value="oracle">Oracle Database</option>
                    <option value="mysql" selected>MySQL</option>
                    <option value="postgres">PostgreSQL</option>
                </select>
            </div>
            
            <div class="control-group">
                <label for="audit-level"><i class="fas fa-shield-alt"></i> 审核严格级别</label>
                <select id="audit-level">
                    <option value="low">低 - 仅关键问题</option>
                    <option value="medium" selected>中 - 推荐级别</option>
                    <option value="high">高 - 全面检查</option>
                    <option value="strict">严格 - 生产环境标准</option>
                </select>
            </div>
            
            <div class="control-group">
                <button id="analyze-btn">
                    <i class="fas fa-search"></i> 分析SQL语句
                </button>
                <div class="progress-container" id="progress-container">
                    <div class="progress-bar" id="progress-bar"></div>
                </div>
            </div>
        </div>
        
        <div class="stats">
            <div class="stat-item">
                <div class="stat-value error-value" id="error-count">0</div>
                <div class="stat-label">严重错误</div>
            </div>
            <div class="stat-item">
                <div class="stat-value warning-value" id="warning-count">0</div>
                <div class="stat-label">性能警告</div>
            </div>
            <div class="stat-item">
                <div class="stat-value vault-value" id="vault-count">0</div>
                <div class="stat-label">金库命令</div>
            </div>
            <div class="stat-item">
                <div class="stat-value success-value" id="success-count">0</div>
                <div class="stat-label">通过检查</div>
            </div>
            <div class="stat-item">
                <div class="stat-value suggestion-value" id="suggestion-count">0</div>
                <div class="stat-label">优化建议</div>
            </div>
        </div>
        
        <div class="main-content">
            <div class="panel">
                <div class="panel-header">
                    <i class="fas fa-code"></i> SQL输入
                </div>
                <div class="panel-content">
                    <textarea id="sql-input" placeholder="在此输入SQL语句...">SELECT e.employee_id, e.first_name, e.last_name, d.department_name, 
    (SELECT COUNT(*) FROM projects p WHERE p.manager_id = e.employee_id) AS project_count
FROM employees e
JOIN departments d ON e.department_id = d.department_id
WHERE e.hire_date > '2020-01-01'
ORDER BY e.last_name, e.first_name;

UPDATE employees
SET salary = salary * 1.05
WHERE department_id = 10;

DELETE FROM order_details
WHERE order_id IN (SELECT order_id FROM orders WHERE order_date < '2019-01-01');

CREATE INDEX idx_employee_name ON employees(last_name, first_name);

GRANT SELECT ON employees TO public;

-- 金库命令示例
DROP TABLE temp_data;
TRUNCATE TABLE audit_log;
ALTER TABLE employees ADD COLUMN salary_history TEXT;
REVOKE ALL ON employees FROM public;
FLUSH PRIVILEGES;
COMMIT;</textarea>
                </div>
            </div>
            
            <div class="panel">
                <div class="panel-header">
                    <i class="fas fa-clipboard-check"></i> 专业审核结果
                </div>
                <div class="panel-content">
                    <div class="results-container" id="results-container">
                        <div class="result-item info">
                            <div class="result-icon"><i class="fas fa-info-circle"></i></div>
                            <div class="result-content">
                                <h3>SQL审核专家系统</h3>
                                <p>输入SQL语句并点击"分析SQL语句"按钮开始专业审核</p>
                                <p>系统将检测语法错误、性能问题、安全隐患和金库命令</p>
                                <div class="vault-commands">
                                    <h4><i class="fas fa-vault"></i> 金库命令监控</h4>
                                    <div class="vault-command-list">
                                        <span class="vault-command">INSERT</span>
                                        <span class="vault-command">DELETE</span>
                                        <span class="vault-command">UPDATE</span>
                                        <span class="vault-command">ALTER</span>
                                        <span class="vault-command">TRUNCATE</span>
                                        <span class="vault-command">DROP</span>
                                        <span class="vault-command">GRANT</span>
                                        <span class="vault-command">REVOKE</span>
                                        <span class="vault-command">FLUSH</span>
                                        <span class="vault-command">COMMIT</span>
                                        <span class="vault-command">ROLLBACK</span>
                                    </div>
                                    <p style="margin-transform: translateY( 10px; font-size: 0.9rem);">这些命令需要额外授权,系统将进行特殊标记</p>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
        
        <footer>
            <p>SQL审核专家系统 v3.2 &copy; 2025 | 新增智能SQL分析引擎 | 专业数据库管理解决方案</p>
        </footer>
    </div>

    <script>
        document.addEventListener('DOMContentLoaded'function() {
            const analyzeBtn = document.getElementById('analyze-btn');
            const sqlInput = document.getElementById('sql-input');
            const resultsContainer = document.getElementById('results-container');
            const progressContainer = document.getElementById('progress-container');
            const progressBar = document.getElementById('progress-bar');
            const successCount = document.getElementById('success-count');
            const warningCount = document.getElementById('warning-count');
            const errorCount = document.getElementById('error-count');
            const suggestionCount = document.getElementById('suggestion-count');
            const vaultCount = document.getElementById('vault-count');
            
            定义金库命令(敏感命令)
            const vaultCommands = [
                'insert''delete''update''alter''truncate''drop',
                'mysqladmin''mysqldump''mysqld''grant''create''set',
                'rename''source''revoke''flush''load''import',
                'shutdown''startup''flushall''flushdb''bgrewriteaof',
                'push''pull''pop''inc''remove''call''replace',
                'commit''rollback''lock''unlock'
            ];
            
            analyzeBtn.addEventListener('click'function() {
                const sql = sqlInput.value.trim();
                const dbType = document.getElementById('db-type').value;
                const auditLevel = document.getElementById('audit-level').value;
                
                if (!sql) {
                    alert('请输入SQL语句!');
                    return;
                }
                
                / 显示进度条
                progressContainer.style.display = 'block';
                progressBar.style.width = '0%';
                
                // 更新按钮状态
                analyzeBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> 分析中...';
                analyzeBtn.disabled = true;
                
                // 清空结果容器
                resultsContainer.innerHTML = '';
                
                // 模拟进度
                let progress = 0;
                const progressInterval = setInterval(() => {
                    progress += 5;
                    progressBar.style.width = `${progress}%`;
                    if (progress >= 100) {
                        clearInterval(progressInterval);
                    }
                }, 100);
                
                // 开始计时
                const startTime = new Date().getTime();
                
                // 模拟分析过程
                setTimeout(() => {
                    // 清空进度条
                    clearInterval(progressInterval);
                    progressBar.style.width = '100%';
                    
                    // 统计结果
                    let success = 0, warning = 0, error = 0, suggestion = 0, vault = 0;
                    
                    // SQL语句解析(简化处理)
                    const sqlLower = sql.toLowerCase();
                    const statements = sql.split(';').filter(s => s.trim() !== '');
                    
                    // 检测金库命令
                    for (const cmd of vaultCommands) {
                        if (sqlLower.includes(cmd)) {
                            vault++;
                            
                            const resultElement = document.createElement('div');
                            resultElement.className = 'result-item vault';
                            
                            let content = '';
                            let recommendation = '';
                            
                            // 根据具体命令生成内容
                            switch(cmd) {
                                case 'drop':
                                    content = '检测到DROP命令:此操作将永久删除数据库对象';
                                    recommendation = 'DROP操作不可逆,执行前需进行备份并确保有回滚计划';
                                    break;
                                case 'truncate':
                                    content = '检测到TRUNCATE命令:此操作将立即清空表数据';
                                    recommendation = 'TRUNCATE操作不可回滚,建议改用DELETE并添加WHERE条件';
                                    break;
                                case 'grant':
                                    content = '检测到GRANT命令:此操作将修改数据库权限';
                                    recommendation = '权限变更需经过安全团队审批,确保符合最小权限原则';
                                    break;
                                case 'revoke':
                                    content = '检测到REVOKE命令:此操作将收回数据库权限';
                                    recommendation = '权限变更需经过安全团队审批,确保不影响关键业务流程';
                                    break;
                                case 'alter':
                                    content = '检测到ALTER命令:此操作将修改数据库结构';
                                    recommendation = '表结构变更需在维护窗口执行,确保不影响在线业务';
                                    break;
                                case 'commit':
                                    content = '检测到COMMIT命令:此操作将提交事务';
                                    recommendation = '确保事务操作已正确测试,避免提交错误数据';
                                    break;
                                case 'delete':
                                    content = '检测到DELETE命令:此操作将删除数据';
                                    recommendation = 'DELETE操作需添加WHERE条件,避免全表删除';
                                    break;
                                default:
                                    content = `检测到${cmd.toUpperCase()}命令:此操作需要额外授权`;
                                    recommendation = '此类命令需要DBA审批和双重确认,确保操作已获得授权并记录审计日志';
                            }
                            
                            resultElement.innerHTML = `
                                <div class="result-icon"><i class="fas fa-shield-alt"></i></div>
                                <div class="result-content">
                                    <h3>金库命令检测 <span class="rule-tag tag-vault">金库命令</span></h3>
                                    <p>${content}</p>
                                    <div class="vault-recommendation">
                                        <strong>安全建议:</strong> ${recommendation}
                                    </div>
                                    <p class="db-hint"><i class="fas fa-database"></i> 数据库: ${dbType.toUpperCase()} | 规则级别: 关键</p>
                                </div>
                            `;
                            resultsContainer.appendChild(resultElement);
                        }
                    }
                    
                    // 检测常见SQL问题
                    if (sqlLower.includes("select *")) {
                        warning++;
                        const resultElement = document.createElement('div');
                        resultElement.className = 'result-item warning';
                        resultElement.innerHTML = `
                            <div class="result-icon"><i class="fas fa-asterisk"></i></div>
                            <div class="result-content">
                                <h3>SELECT * 警告 <span class="rule-tag tag-performance">性能</span></h3>
                                <p>避免使用SELECT *,明确指定所需列</p>
                                <div class="recommendation">
                                    <strong>推荐方案:</strong> 明确指定所需列,例如: SELECT id, name, title FROM employees
                                </div>
                                <p class="db-hint"><i class="fas fa-database"></i> 数据库: ${dbType.toUpperCase()} | 规则级别: 重要</p>
                            </div>
                        `;
                        resultsContainer.appendChild(resultElement);
                    }
                    
                    if (sqlLower.includes("delete") && !sqlLower.includes("where")) {
                        error++;
                        const resultElement = document.createElement('div');
                        resultElement.className = 'result-item error';
                        resultElement.innerHTML = `
                            <div class="result-icon"><i class="fas fa-ban"></i></div>
                            <div class="result-content">
                                <h3>DELETE无WHERE条件 <span class="rule-tag tag-security">安全</span></h3>
                                <p>DELETE语句缺少WHERE条件,将删除全表数据</p>
                                <div class="recommendation">
                                    <strong>安全建议:</strong> 添加WHERE条件限制删除范围
                                </div>
                                <p class="db-hint"><i class="fas fa-database"></i> 数据库: ${dbType.toUpperCase()} | 规则级别: 关键</p>
                            </div>
                        `;
                        resultsContainer.appendChild(resultElement);
                    }
                    
                    if (sqlLower.includes("join") && !sqlLower.includes("on")) {
                        error++;
                        const resultElement = document.createElement('div');
                        resultElement.className = 'result-item error';
                        resultElement.innerHTML = `
                            <div class="result-icon"><i class="fas fa-link"></i></div>
                            <div class="result-content">
                                <h3>JOIN条件缺失 <span class="rule-tag tag-design">设计</span></h3>
                                <p>JOIN语句缺少ON条件,可能导致笛卡尔积</p>
                                <div class="recommendation">
                                    <strong>推荐方案:</strong> 为JOIN添加ON条件,指定关联字段
                                </div>
                                <p class="db-hint"><i class="fas fa-database"></i> 数据库: ${dbType.toUpperCase()} | 规则级别: 关键</p>
                            </div>
                        `;
                        resultsContainer.appendChild(resultElement);
                    }
                    
                    if (sqlLower.includes("grant") && sqlLower.includes("public")) {
                        warning++;
                        const resultElement = document.createElement('div');
                        resultElement.className = 'result-item warning';
                        resultElement.innerHTML = `
                            <div class="result-icon"><i class="fas fa-lock"></i></div>
                            <div class="result-content">
                                <h3>权限过大 <span class="rule-tag tag-security">安全</span></h3>
                                <p>GRANT语句将敏感数据表授权给PUBLIC角色</p>
                                <div class="recommendation">
                                    <strong>安全建议:</strong> 使用最小权限原则,仅授权给必要用户
                                </div>
                                <p class="db-hint"><i class="fas fa-database"></i> 数据库: ${dbType.toUpperCase()} | 规则级别: 重要</p>
                            </div>
                        `;
                        resultsContainer.appendChild(resultElement);
                    }
                    
                    // 检测子查询性能问题
                    if (sqlLower.match(/select\s+.*?\s+from.*?\s+where\s+.*?\(\s*select\s+.*?\s+from/)) {
                        suggestion++;
                        const resultElement = document.createElement('div');
                        resultElement.className = 'result-item suggestion';
                        resultElement.innerHTML = `
                            <div class="result-icon"><i class="fas fa-tachometer-alt"></i></div>
                            <div class="result-content">
                                <h3>子查询性能问题 <span class="rule-tag tag-performance">性能</span></h3>
                                <p>相关子查询可能导致性能问题,特别是在大表上</p>
                                <div class="recommendation">
                                    <strong>推荐方案:</strong> 考虑使用JOIN重写或使用临时表优化
                                </div>
                                <p class="db-hint"><i class="fas fa-database"></i> 数据库: ${dbType.toUpperCase()} | 规则级别: 推荐</p>
                            </div>
                        `;
                        resultsContainer.appendChild(resultElement);
                    }
                    
                    // 检测索引创建
                    if (sqlLower.includes("create index")) {
                        success++;
                        const resultElement = document.createElement('div');
                        resultElement.className = 'result-item success';
                        resultElement.innerHTML = `
                            <div class="result-icon"><i class="fas fa-check-circle"></i></div>
                            <div class="result-content">
                                <h3>索引创建合理 <span class="rule-tag tag-best">最佳实践</span></h3>
                                <p>索引设计合理,有助于提高查询性能</p>
                                <div class="recommendation">
                                    <strong>建议:</strong> 监控索引使用情况,避免创建过多索引
                                </div>
                                <p class="db-hint"><i class="fas fa-database"></i> 数据库: ${dbType.toUpperCase()} | 规则级别: 推荐</p>
                            </div>
                        `;
                        resultsContainer.appendChild(resultElement);
                    }
                    
                    // 检测隐式类型转换
                    if (sqlLower.match(/where\s+\w+\s*=\s*['"]\d+['"]/)) {
                        warning++;
                        const resultElement = document.createElement('div');
                        resultElement.className = 'result-item warning';
                        resultElement.innerHTML = `
                            <div class="
result-icon"><i class="fas fa-columns"></i></div>
                            <div class="
result-content">
                                <h3>隐式类型转换 <span class="
rule-tag tag-performance">性能</span></h3>
                                <p>WHERE条件中存在隐式类型转换,可能导致索引失效</p>
                                <div class="
recommendation">
                                    <strong>推荐方案:</strong> 确保WHERE条件中的列和值数据类型一致
                                </div>
                                <p class="
db-hint"><i class="fas fa-database"></i> 数据库: ${dbType.toUpperCase()} | 规则级别: 重要</p>
                            </div>
                        `;
                        resultsContainer.appendChild(resultElement);
                    }
                    
                    // 检测大表操作
                    if (sqlLower.includes("
delete") || sqlLower.includes("update")) {
                        const tableMatch = sqlLower.match(/(?:from|update)\s+(\w+)/);
                        if (tableMatch) {
                            const tableName = tableMatch[1];
                            warning++;
                            const resultElement = document.createElement('div');
                            resultElement.className = 'result-item warning';
                            resultElement.innerHTML = `
                                <div class="
result-icon"><i class="fas fa-server"></i></div>
                                <div class="
result-content">
                                    <h3>大表操作风险 <span class="
rule-tag tag-performance">性能</span></h3>
                                    <p>在表 ${tableName} 上执行数据修改操作,可能影响性能</p>
                                    <div class="
recommendation">
                                        <strong>推荐方案:</strong> 分批操作,每批处理1000条记录
                                    </div>
                                    <p class="
db-hint"><i class="fas fa-database"></i> 数据库: ${dbType.toUpperCase()} | 规则级别: 重要</p>
                                </div>
                            `;
                            resultsContainer.appendChild(resultElement);
                        }
                    }
                    
                    // 检测日期格式
                    if (sqlLower.match(/\d{4}-\d{2}-\d{2}/)) {
                        suggestion++;
                        const resultElement = document.createElement('div');
                        resultElement.className = 'result-item suggestion';
                        resultElement.innerHTML = `
                            <div class="
result-icon"><i class="fas fa-calendar"></i></div>
                            <div class="
result-content">
                                <h3>日期格式建议 <span class="
rule-tag tag-design">设计</span></h3>
                                <p>日期字面值使用ISO格式(YYYY-MM-DD),确保跨数据库兼容性</p>
                                <p class="
db-hint"><i class="fas fa-database"></i> 数据库: ${dbType.toUpperCase()} | 规则级别: 推荐</p>
                            </div>
                        `;
                        resultsContainer.appendChild(resultElement);
                    }
                    
                    // 如果没有检测到任何问题
                    if (resultsContainer.children.length === 0) {
                        success++;
                        const resultElement = document.createElement('div');
                        resultElement.className = 'result-item success';
                        resultElement.innerHTML = `
                            <div class="
result-icon"><i class="fas fa-check-circle"></i></div>
                            <div class="
result-content">
                                <h3>审核完成</h3>
                                <p>未发现任何问题,SQL语句符合最佳实践</p>
                                <p class="
db-hint"><i class="fas fa-database"></i> 数据库: ${dbType.toUpperCase()}</p>
                            </div>
                        `;
                        resultsContainer.appendChild(resultElement);
                    }
                    
                    // 更新统计信息
                    errorCount.textContent = error;
                    warningCount.textContent = warning;
                    successCount.textContent = success;
                    suggestionCount.textContent = suggestion;
                    vaultCount.textContent = vault;
                    
                    // 计算分析时间
                    const endTime = new Date().getTime();
                    const timeTaken = (endTime - startTime) / 1000;
                    
                    // 恢复按钮状态
                    setTimeout(() => {
                        analyzeBtn.innerHTML = '<i class="
fas fa-search"></i> 分析SQL语句';
                        analyzeBtn.disabled = false;
                        progressContainer.style.display = 'none';
                    }, 500);
                }, 1800);
            });
        });
    </script>
</body>
</html>

 



END
往期文章回顾

文中的概念来源于互联网,如有侵权,请联系我删除。

欢迎关注公众号:小周的数据库进阶之路,一起交流AI、数据库、中间件和云计算等技术。如果觉得读完本文有收获,可以转发给其他朋友,大家一起学习进步!感兴趣的朋友可以加我微信,拉您进群与业界的大佬们一起交流学习。



文章转载自小周的数据库进阶之路,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论