MySQL__MongoDB__Redis 入门

一、MySQL 连接与基础操作

1.1 连接数据库
sql 复制代码
-- 基本连接
mysql -u root -p
Enter password: ******

-- 指定主机和端口
mysql -h localhost -P 3306 -u username -p

-- 连接指定数据库
mysql -u username -p database_name

-- 使用SSL连接
mysql --ssl-ca=ca.pem --ssl-cert=client-cert.pem --ssl-key=client-key.pem -u root -p
1.2 数据库基本操作
sql 复制代码
-- 查看所有数据库
SHOW DATABASES;

-- 创建数据库
CREATE DATABASE company;
CREATE DATABASE IF NOT EXISTS company;

-- 指定字符集和排序规则
CREATE DATABASE company 
CHARACTER SET utf8mb4 
COLLATE utf8mb4_unicode_ci;

-- 选择使用数据库
USE company;

-- 删除数据库
DROP DATABASE company;
DROP DATABASE IF EXISTS company;

-- 查看当前数据库
SELECT DATABASE();

-- 查看数据库创建语句
SHOW CREATE DATABASE company;

二、MySQL DDL 数据定义语言

2.1 创建表
sql 复制代码
-- 基本创建表
CREATE TABLE employees (
    id INT PRIMARY KEY AUTO_INCREMENT,
    first_name VARCHAR(50) NOT NULL,
    last_name VARCHAR(50) NOT NULL,
    email VARCHAR(100) UNIQUE,
    hire_date DATE DEFAULT (CURRENT_DATE),
    salary DECIMAL(10,2),
    department_id INT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

-- 带索引和注释的表
CREATE TABLE departments (
    department_id INT PRIMARY KEY AUTO_INCREMENT COMMENT '部门ID',
    department_name VARCHAR(100) NOT NULL COMMENT '部门名称',
    manager_id INT COMMENT '经理ID',
    location VARCHAR(200) COMMENT '办公地点',
    INDEX idx_department_name (department_name),
    INDEX idx_manager (manager_id)
) COMMENT='部门信息表' ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
2.2 修改表结构
sql 复制代码
-- 添加列
ALTER TABLE employees ADD COLUMN phone VARCHAR(20) AFTER email;

-- 修改列
ALTER TABLE employees MODIFY COLUMN salary DECIMAL(12,2) NOT NULL DEFAULT 0;

-- 重命名列
ALTER TABLE employees CHANGE COLUMN phone mobile VARCHAR(20);

-- 删除列
ALTER TABLE employees DROP COLUMN mobile;

-- 添加索引
ALTER TABLE employees ADD INDEX idx_email (email);
ALTER TABLE employees ADD UNIQUE INDEX uk_email (email);
ALTER TABLE employees ADD FULLTEXT INDEX ft_name (first_name, last_name);

-- 删除索引
ALTER TABLE employees DROP INDEX idx_email;

-- 重命名表
RENAME TABLE employees TO staff;
ALTER TABLE staff RENAME TO employees;
2.3 删除表
sql 复制代码
-- 删除表
DROP TABLE employees;

-- 安全删除表
DROP TABLE IF EXISTS employees;

-- 清空表数据(重置自增ID)
TRUNCATE TABLE employees;

三、MySQL DML 数据操作语言

3.1 插入数据
sql 复制代码
-- 插入单条数据
INSERT INTO employees (first_name, last_name, email, salary, department_id)
VALUES ('张', '三', 'zhangsan@example.com', 5000.00, 1);

-- 插入多条数据
INSERT INTO employees (first_name, last_name, email, salary, department_id)
VALUES 
    ('李', '四', 'lisi@example.com', 6000.00, 1),
    ('王', '五', 'wangwu@example.com', 7000.00, 2),
    ('赵', '六', 'zhaoliu@example.com', 5500.00, 3);

-- 插入时忽略错误
INSERT IGNORE INTO employees (first_name, last_name, email, salary, department_id)
VALUES ('张', '三', 'zhangsan@example.com', 5000.00, 1);

-- 插入并替换(存在则更新)
REPLACE INTO employees (id, first_name, last_name, email)
VALUES (1, '张', '三', 'zhangsan@example.com');

-- 从查询结果插入
INSERT INTO employee_backup 
SELECT * FROM employees WHERE hire_date < '2020-01-01';
3.2 更新数据
sql 复制代码
-- 更新单条数据
UPDATE employees 
SET salary = 5500.00, updated_at = CURRENT_TIMESTAMP 
WHERE id = 1;

-- 更新多条数据
UPDATE employees 
SET salary = salary * 1.1 
WHERE department_id = 1;

-- 使用子查询更新
UPDATE employees e
SET salary = (
    SELECT AVG(salary) 
    FROM employees 
    WHERE department_id = e.department_id
)
WHERE department_id = 2;

-- 使用JOIN更新
UPDATE employees e
JOIN departments d ON e.department_id = d.department_id
SET e.salary = e.salary * 1.05
WHERE d.department_name = '技术部';

-- 批量更新
UPDATE employees 
SET status = 'active'
WHERE id IN (1, 3, 5, 7, 9);
3.3 删除数据
sql 复制代码
-- 删除单条数据
DELETE FROM employees WHERE id = 1;

-- 删除多条数据
DELETE FROM employees WHERE department_id = 3;

-- 使用子查询删除
DELETE FROM employees 
WHERE department_id IN (
    SELECT department_id 
    FROM departments 
    WHERE location = '北京'
);

-- 使用JOIN删除
DELETE e 
FROM employees e
JOIN departments d ON e.department_id = d.department_id
WHERE d.department_name = '测试部';

-- 清空表(比DELETE快,不可回滚)
TRUNCATE TABLE temp_data;

四、MySQL DQL 数据查询语言

4.1 基础查询
sql 复制代码
-- 查询所有列
SELECT * FROM employees;

-- 查询指定列
SELECT first_name, last_name, salary FROM employees;

-- 使用别名
SELECT 
    first_name AS '名',
    last_name AS '姓',
    salary AS '月薪',
    salary * 12 AS '年薪'
FROM employees;

-- 去重查询
SELECT DISTINCT department_id FROM employees;

-- 条件查询
SELECT * FROM employees 
WHERE salary > 5000 AND department_id = 1;

-- NULL值处理
SELECT * FROM employees 
WHERE email IS NULL;

SELECT * FROM employees 
WHERE email IS NOT NULL;

-- 模糊查询
SELECT * FROM employees 
WHERE first_name LIKE '张%';  -- 以张开头的

SELECT * FROM employees 
WHERE email LIKE '%@example.com';  -- 以@example.com结尾的

SELECT * FROM employees 
WHERE last_name LIKE '_三';  -- 第二个字为三的
4.2 排序和限制
sql 复制代码
-- 单字段排序
SELECT * FROM employees 
ORDER BY salary DESC;

-- 多字段排序
SELECT * FROM employees 
ORDER BY department_id ASC, salary DESC;

-- 限制返回数量
SELECT * FROM employees 
ORDER BY hire_date DESC 
LIMIT 10;

-- 分页查询
SELECT * FROM employees 
ORDER BY id 
LIMIT 10 OFFSET 20;  -- 第3页,每页10条

-- 简化分页写法
SELECT * FROM employees 
ORDER BY id 
LIMIT 20, 10;  -- 从第20条开始,取10条
4.3 聚合函数
sql 复制代码
-- 基本聚合
SELECT 
    COUNT(*) AS '员工总数',
    COUNT(DISTINCT department_id) AS '部门数量',
    AVG(salary) AS '平均工资',
    MAX(salary) AS '最高工资',
    MIN(salary) AS '最低工资',
    SUM(salary) AS '工资总额'
FROM employees;

-- 分组聚合
SELECT 
    department_id,
    COUNT(*) AS '人数',
    AVG(salary) AS '平均工资',
    MAX(salary) AS '最高工资'
FROM employees
GROUP BY department_id;

-- 分组后筛选
SELECT 
    department_id,
    COUNT(*) AS '人数'
FROM employees
GROUP BY department_id
HAVING COUNT(*) > 5;

-- 分组后排序
SELECT 
    department_id,
    AVG(salary) AS avg_salary
FROM employees
GROUP BY department_id
ORDER BY avg_salary DESC;
4.4 多表连接查询
sql 复制代码
-- INNER JOIN(内连接)
SELECT 
    e.first_name,
    e.last_name,
    e.salary,
    d.department_name
FROM employees e
INNER JOIN departments d ON e.department_id = d.department_id;

-- LEFT JOIN(左连接)
SELECT 
    e.first_name,
    e.last_name,
    d.department_name
FROM employees e
LEFT JOIN departments d ON e.department_id = d.department_id;

-- RIGHT JOIN(右连接)
SELECT 
    e.first_name,
    e.last_name,
    d.department_name
FROM employees e
RIGHT JOIN departments d ON e.department_id = d.department_id;

-- FULL OUTER JOIN(MySQL不支持,用UNION模拟)
SELECT 
    e.first_name,
    e.last_name,
    d.department_name
FROM employees e
LEFT JOIN departments d ON e.department_id = d.department_id
UNION
SELECT 
    e.first_name,
    e.last_name,
    d.department_name
FROM employees e
RIGHT JOIN departments d ON e.department_id = d.department_id;

-- 多表连接
SELECT 
    e.first_name,
    e.last_name,
    d.department_name,
    l.location_name
FROM employees e
JOIN departments d ON e.department_id = d.department_id
JOIN locations l ON d.location_id = l.location_id;
4.5 子查询
sql 复制代码
-- 标量子查询(返回单个值)
SELECT 
    first_name,
    last_name,
    salary,
    (SELECT AVG(salary) FROM employees) AS avg_salary
FROM employees;

-- 列子查询(返回一列)
SELECT * FROM employees 
WHERE department_id IN (
    SELECT department_id 
    FROM departments 
    WHERE location = '上海'
);

-- 行子查询(返回一行)
SELECT * FROM employees 
WHERE (department_id, salary) = (
    SELECT department_id, MAX(salary)
    FROM employees 
    GROUP BY department_id 
    ORDER BY MAX(salary) DESC 
    LIMIT 1
);

-- 表子查询(返回多行多列)
SELECT * FROM (
    SELECT 
        department_id,
        COUNT(*) as emp_count,
        AVG(salary) as avg_salary
    FROM employees
    GROUP BY department_id
) AS dept_stats
WHERE emp_count > 10;

-- EXISTS子查询
SELECT * FROM departments d
WHERE EXISTS (
    SELECT 1 
    FROM employees e
    WHERE e.department_id = d.department_id
    AND e.salary > 10000
);

-- NOT EXISTS子查询
SELECT * FROM departments d
WHERE NOT EXISTS (
    SELECT 1 
    FROM employees e
    WHERE e.department_id = d.department_id
);
4.6 组合查询
sql 复制代码
-- UNION(去重合并)
SELECT first_name, last_name FROM employees WHERE department_id = 1
UNION
SELECT first_name, last_name FROM employees WHERE salary > 8000;

-- UNION ALL(不去重合并)
SELECT first_name, last_name FROM employees WHERE department_id = 1
UNION ALL
SELECT first_name, last_name FROM employees WHERE salary > 8000;

-- INTERSECT(交集,MySQL 8.0.31+)
SELECT first_name, last_name FROM employees WHERE department_id = 1
INTERSECT
SELECT first_name, last_name FROM employees WHERE salary > 8000;

-- EXCEPT(差集,MySQL 8.0.31+)
SELECT first_name, last_name FROM employees WHERE department_id = 1
EXCEPT
SELECT first_name, last_name FROM employees WHERE salary > 8000;
4.7 窗口函数
sql 复制代码
-- 排名函数
SELECT 
    first_name,
    last_name,
    salary,
    ROW_NUMBER() OVER (ORDER BY salary DESC) AS row_num,
    RANK() OVER (ORDER BY salary DESC) AS rank_num,
    DENSE_RANK() OVER (ORDER BY salary DESC) AS dense_rank_num,
    NTILE(4) OVER (ORDER BY salary DESC) AS quartile
FROM employees;

-- 聚合窗口函数
SELECT 
    first_name,
    last_name,
    department_id,
    salary,
    AVG(salary) OVER (PARTITION BY department_id) AS dept_avg_salary,
    SUM(salary) OVER (PARTITION BY department_id) AS dept_total_salary,
    COUNT(*) OVER (PARTITION BY department_id) AS dept_emp_count
FROM employees;

-- 前后值函数
SELECT 
    first_name,
    last_name,
    hire_date,
    salary,
    LAG(salary) OVER (ORDER BY hire_date) AS prev_salary,
    LEAD(salary) OVER (ORDER BY hire_date) AS next_salary,
    FIRST_VALUE(salary) OVER (PARTITION BY department_id ORDER BY salary) AS lowest_salary,
    LAST_VALUE(salary) OVER (PARTITION BY department_id ORDER BY salary) AS highest_salary
FROM employees;

-- 累积计算
SELECT 
    hire_date,
    salary,
    SUM(salary) OVER (ORDER BY hire_date) AS running_total,
    AVG(salary) OVER (ORDER BY hire_date ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) AS moving_avg
FROM employees;

五、MySQL 索引管理

5.1 创建索引
sql 复制代码
-- 创建普通索引
CREATE INDEX idx_last_name ON employees(last_name);

-- 创建唯一索引
CREATE UNIQUE INDEX uk_email ON employees(email);

-- 创建复合索引
CREATE INDEX idx_name_department ON employees(last_name, first_name, department_id);

-- 创建前缀索引
CREATE INDEX idx_email_prefix ON employees(email(20));

-- 创建全文索引(InnoDB支持)
CREATE FULLTEXT INDEX ft_content ON articles(title, content);

-- 创建空间索引
CREATE SPATIAL INDEX sp_location ON places(location);
5.2 查看和删除索引
sql 复制代码
-- 查看表索引
SHOW INDEX FROM employees;

-- 查看索引信息
SELECT 
    TABLE_NAME,
    INDEX_NAME,
    COLUMN_NAME,
    SEQ_IN_INDEX,
    INDEX_TYPE,
    CARDINALITY
FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = 'company'
AND TABLE_NAME = 'employees';

-- 删除索引
DROP INDEX idx_last_name ON employees;

-- 优化表(重建索引)
OPTIMIZE TABLE employees;

-- 分析表(更新统计信息)
ANALYZE TABLE employees;

-- 检查表状态
CHECK TABLE employees;

六、MySQL 事务管理

6.1 事务控制
sql 复制代码
-- 开始事务
START TRANSACTION;
-- 或者
BEGIN;
-- 或者
BEGIN WORK;

-- 提交事务
COMMIT;

-- 回滚事务
ROLLBACK;

-- 设置保存点
SAVEPOINT point1;

-- 回滚到保存点
ROLLBACK TO point1;

-- 释放保存点
RELEASE SAVEPOINT point1;

-- 完整事务示例
START TRANSACTION;

INSERT INTO orders (customer_id, amount) VALUES (1, 100.00);
UPDATE accounts SET balance = balance - 100 WHERE customer_id = 1;

-- 可以添加检查逻辑
SELECT balance FROM accounts WHERE customer_id = 1 FOR UPDATE;

COMMIT;
6.2 事务隔离级别
sql 复制代码
-- 查看当前隔离级别
SELECT @@transaction_isolation;

-- 设置会话隔离级别
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;

-- 设置全局隔离级别
SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ;

-- 隔离级别说明:
-- READ UNCOMMITTED: 读取未提交数据(脏读)
-- READ COMMITTED: 读取已提交数据(Oracle默认)
-- REPEATABLE READ: 可重复读(MySQL默认)
-- SERIALIZABLE: 串行化

七、MySQL 存储过程和函数

7.1 存储过程
sql 复制代码
-- 创建存储过程
DELIMITER $$

CREATE PROCEDURE GetEmployeeCount(IN dept_id INT, OUT emp_count INT)
BEGIN
    SELECT COUNT(*) INTO emp_count
    FROM employees
    WHERE department_id = dept_id;
END$$

DELIMITER ;

-- 调用存储过程
CALL GetEmployeeCount(1, @count);
SELECT @count;

-- 带条件的存储过程
DELIMITER $$

CREATE PROCEDURE UpdateSalary(
    IN emp_id INT,
    IN increase_percent DECIMAL(5,2),
    OUT old_salary DECIMAL(10,2),
    OUT new_salary DECIMAL(10,2)
)
BEGIN
    DECLARE current_salary DECIMAL(10,2);
    
    -- 获取当前工资
    SELECT salary INTO current_salary
    FROM employees
    WHERE id = emp_id;
    
    SET old_salary = current_salary;
    SET new_salary = current_salary * (1 + increase_percent / 100);
    
    -- 更新工资
    UPDATE employees
    SET salary = new_salary
    WHERE id = emp_id;
    
    -- 记录日志
    INSERT INTO salary_history (employee_id, old_salary, new_salary, change_date)
    VALUES (emp_id, old_salary, new_salary, NOW());
END$$

DELIMITER ;
7.2 函数
sql 复制代码
-- 创建函数
DELIMITER $$

CREATE FUNCTION CalculateBonus(salary DECIMAL(10,2), performance_rating INT)
RETURNS DECIMAL(10,2)
DETERMINISTIC
BEGIN
    DECLARE bonus DECIMAL(10,2);
    
    IF performance_rating >= 9 THEN
        SET bonus = salary * 0.3;
    ELSEIF performance_rating >= 7 THEN
        SET bonus = salary * 0.2;
    ELSEIF performance_rating >= 5 THEN
        SET bonus = salary * 0.1;
    ELSE
        SET bonus = 0;
    END IF;
    
    RETURN bonus;
END$$

DELIMITER ;

-- 使用函数
SELECT 
    first_name,
    last_name,
    salary,
    CalculateBonus(salary, 8) AS bonus
FROM employees;

八、MySQL 触发器

sql 复制代码
-- 创建触发器
DELIMITER $$

CREATE TRIGGER before_employee_insert
BEFORE INSERT ON employees
FOR EACH ROW
BEGIN
    IF NEW.email IS NULL THEN
        SET NEW.email = CONCAT(LOWER(NEW.first_name), '.', LOWER(NEW.last_name), '@company.com');
    END IF;
    
    SET NEW.created_at = NOW();
    SET NEW.updated_at = NOW();
END$$

DELIMITER ;

-- 更新触发器
DELIMITER $$

CREATE TRIGGER before_employee_update
BEFORE UPDATE ON employees
FOR EACH ROW
BEGIN
    SET NEW.updated_at = NOW();
END$$

DELIMITER ;

-- 删除触发器
DROP TRIGGER IF EXISTS before_employee_insert;

九、MySQL 视图

sql 复制代码
-- 创建视图
CREATE VIEW employee_details AS
SELECT 
    e.id,
    CONCAT(e.first_name, ' ', e.last_name) AS full_name,
    e.email,
    e.salary,
    d.department_name,
    e.hire_date
FROM employees e
JOIN departments d ON e.department_id = d.department_id
WHERE e.status = 'active';

-- 使用视图
SELECT * FROM employee_details WHERE department_name = '技术部';

-- 创建可更新视图
CREATE VIEW active_employees AS
SELECT id, first_name, last_name, email, department_id
FROM employees
WHERE status = 'active'
WITH CHECK OPTION;

-- 查看视图定义
SHOW CREATE VIEW employee_details;

-- 删除视图
DROP VIEW IF EXISTS employee_details;

PostgreSQL 详细教程

一、PostgreSQL 连接与基础操作

1.1 连接数据库
bash 复制代码
# 连接本地数据库
psql -U username -d database_name

# 指定主机和端口
psql -h localhost -p 5432 -U username -d database_name

# 使用连接字符串
psql "host=localhost port=5432 dbname=mydb user=myuser password=mypass"

# 连接后执行SQL文件
psql -U username -d database_name -f script.sql

# 执行单条命令
psql -U username -d database_name -c "SELECT version();"
1.2 数据库基本操作
sql 复制代码
-- 查看所有数据库
\l

-- 创建数据库
CREATE DATABASE company;

-- 指定参数创建
CREATE DATABASE company
WITH 
    ENCODING = 'UTF8'
    LC_COLLATE = 'zh_CN.UTF-8'
    LC_CTYPE = 'zh_CN.UTF-8'
    TEMPLATE = template0;

-- 连接数据库
\c company

-- 查看数据库信息
SELECT datname, encoding, datcollate, datctype 
FROM pg_database;

-- 删除数据库
DROP DATABASE company;

-- 安全删除
DROP DATABASE IF EXISTS company;

-- 重命名数据库
ALTER DATABASE old_name RENAME TO new_name;

二、PostgreSQL DDL 数据定义语言

2.1 创建表
sql 复制代码
-- 基本创建表
CREATE TABLE employees (
    id SERIAL PRIMARY KEY,
    first_name VARCHAR(50) NOT NULL,
    last_name VARCHAR(50) NOT NULL,
    email VARCHAR(100) UNIQUE,
    hire_date DATE DEFAULT CURRENT_DATE,
    salary NUMERIC(10,2),
    department_id INTEGER,
    created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);

-- 带注释的表
COMMENT ON TABLE employees IS '员工信息表';
COMMENT ON COLUMN employees.id IS '员工ID';
COMMENT ON COLUMN employees.email IS '员工邮箱';

-- 继承表(PostgreSQL特有)
CREATE TABLE managers (
    bonus NUMERIC(10,2),
    team_size INTEGER
) INHERITS (employees);

-- 创建分区表
CREATE TABLE sales (
    sale_id SERIAL,
    sale_date DATE NOT NULL,
    amount NUMERIC(10,2),
    region VARCHAR(50)
) PARTITION BY RANGE (sale_date);

-- 创建分区
CREATE TABLE sales_2023_q1 PARTITION OF sales
FOR VALUES FROM ('2023-01-01') TO ('2023-04-01');

CREATE TABLE sales_2023_q2 PARTITION OF sales
FOR VALUES FROM ('2023-04-01') TO ('2023-07-01');
2.2 修改表结构
sql 复制代码
-- 添加列
ALTER TABLE employees ADD COLUMN phone VARCHAR(20);

-- 添加带默认值的列
ALTER TABLE employees 
ADD COLUMN status VARCHAR(20) DEFAULT 'active';

-- 修改列类型
ALTER TABLE employees 
ALTER COLUMN salary TYPE NUMERIC(12,2);

-- 设置列默认值
ALTER TABLE employees 
ALTER COLUMN updated_at SET DEFAULT CURRENT_TIMESTAMP;

-- 删除列默认值
ALTER TABLE employees 
ALTER COLUMN updated_at DROP DEFAULT;

-- 重命名列
ALTER TABLE employees 
RENAME COLUMN phone TO mobile;

-- 添加约束
ALTER TABLE employees 
ADD CONSTRAINT check_salary CHECK (salary >= 0);

-- 删除约束
ALTER TABLE employees 
DROP CONSTRAINT check_salary;

-- 重命名表
ALTER TABLE employees RENAME TO staff;

三、PostgreSQL DML 数据操作语言

3.1 插入数据
sql 复制代码
-- 插入单条数据
INSERT INTO employees (first_name, last_name, email, salary)
VALUES ('张', '三', 'zhangsan@example.com', 5000.00);

-- 插入多条数据
INSERT INTO employees (first_name, last_name, email, salary) VALUES
('李', '四', 'lisi@example.com', 6000.00),
('王', '五', 'wangwu@example.com', 7000.00);

-- 插入并返回ID
INSERT INTO employees (first_name, last_name, email, salary)
VALUES ('赵', '六', 'zhaoliu@example.com', 5500.00)
RETURNING id;

-- 从查询结果插入
INSERT INTO employee_backup 
SELECT * FROM employees WHERE hire_date < '2020-01-01'
RETURNING *;

-- 冲突处理(不存在则插入,存在则更新)
INSERT INTO employees (id, first_name, last_name, email)
VALUES (1, '张', '三', 'zhangsan@example.com')
ON CONFLICT (id) 
DO UPDATE SET 
    first_name = EXCLUDED.first_name,
    last_name = EXCLUDED.last_name,
    email = EXCLUDED.email,
    updated_at = CURRENT_TIMESTAMP;

-- 冲突处理(不存在则插入,存在则忽略)
INSERT INTO employees (id, first_name, last_name, email)
VALUES (1, '张', '三', 'zhangsan@example.com')
ON CONFLICT (id) DO NOTHING;
3.2 更新数据
sql 复制代码
-- 更新数据
UPDATE employees 
SET salary = 5500.00, updated_at = CURRENT_TIMESTAMP 
WHERE id = 1
RETURNING *;

-- 使用FROM子句更新
UPDATE employees e
SET salary = d.avg_salary
FROM (
    SELECT department_id, AVG(salary) as avg_salary
    FROM employees
    GROUP BY department_id
) d
WHERE e.department_id = d.department_id;

-- 使用JOIN更新
UPDATE employees e
SET salary = e.salary * 1.05
FROM departments d
WHERE e.department_id = d.department_id
AND d.department_name = '技术部';

-- 条件更新
UPDATE employees
SET salary = CASE
    WHEN performance_rating >= 9 THEN salary * 1.20
    WHEN performance_rating >= 7 THEN salary * 1.10
    ELSE salary * 1.05
END;
3.3 删除数据
sql 复制代码
-- 删除数据
DELETE FROM employees WHERE id = 1
RETURNING *;

-- 使用USING子句删除
DELETE FROM employees e
USING departments d
WHERE e.department_id = d.department_id
AND d.location = '北京';

-- 清空表
TRUNCATE TABLE employees;

-- 清空表并重置序列
TRUNCATE TABLE employees RESTART IDENTITY;

-- 只清空数据,保留表结构
TRUNCATE TABLE employees CONTINUE IDENTITY;

四、PostgreSQL DQL 数据查询语言

4.1 CTE 公用表表达式
sql 复制代码
-- 基本CTE
WITH department_stats AS (
    SELECT 
        department_id,
        COUNT(*) as emp_count,
        AVG(salary) as avg_salary
    FROM employees
    GROUP BY department_id
)
SELECT * FROM department_stats 
WHERE emp_count > 10;

-- 递归CTE(查询树形结构)
WITH RECURSIVE category_tree AS (
    -- 初始查询(根节点)
    SELECT id, name, parent_id, 1 as level
    FROM categories
    WHERE parent_id IS NULL
    
    UNION ALL
    
    -- 递归查询(子节点)
    SELECT c.id, c.name, c.parent_id, ct.level + 1
    FROM categories c
    JOIN category_tree ct ON c.parent_id = ct.id
)
SELECT * FROM category_tree 
ORDER BY level, id;
4.2 窗口函数
sql 复制代码
-- PostgreSQL窗口函数更强大
SELECT 
    first_name,
    last_name,
    department_id,
    salary,
    -- 排名
    ROW_NUMBER() OVER w AS row_num,
    RANK() OVER w AS rank_num,
    DENSE_RANK() OVER w AS dense_rank,
    -- 聚合
    AVG(salary) OVER w AS dept_avg,
    SUM(salary) OVER w AS dept_total,
    -- 前后值
    LAG(salary) OVER w AS prev_salary,
    LEAD(salary) OVER w AS next_salary,
    -- 百分位
    PERCENT_RANK() OVER w AS percent_rank,
    CUME_DIST() OVER w AS cumulative_dist
FROM employees
WINDOW w AS (PARTITION BY department_id ORDER BY salary DESC)
ORDER BY department_id, salary DESC;

-- 窗口帧子句
SELECT 
    hire_date,
    salary,
    AVG(salary) OVER (
        ORDER BY hire_date
        ROWS BETWEEN 2 PRECEDING AND CURRENT ROW
    ) AS moving_avg_3,
    AVG(salary) OVER (
        ORDER BY hire_date
        RANGE BETWEEN INTERVAL '30 days' PRECEDING AND CURRENT ROW
    ) AS monthly_avg
FROM employees;
4.3 JSON 操作
sql 复制代码
-- 创建JSON字段
CREATE TABLE products (
    id SERIAL PRIMARY KEY,
    name VARCHAR(100),
    attributes JSONB,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- 插入JSON数据
INSERT INTO products (name, attributes) VALUES
('笔记本电脑', '{"brand": "Dell", "ram": "16GB", "storage": "512GB SSD", "color": "silver"}'),
('智能手机', '{"brand": "Apple", "model": "iPhone 14", "color": "black", "storage": "256GB"}');

-- 查询JSON字段
SELECT 
    name,
    attributes->>'brand' as brand,
    attributes->>'color' as color,
    attributes->'storage' as storage
FROM products;

-- JSON条件查询
SELECT * FROM products 
WHERE attributes->>'brand' = 'Apple';

SELECT * FROM products 
WHERE attributes @> '{"color": "black"}';

-- 更新JSON字段
UPDATE products 
SET attributes = attributes || '{"warranty": "2 years"}'::jsonb
WHERE id = 1;

-- JSON函数
SELECT 
    jsonb_pretty(attributes),
    jsonb_array_length(attributes->'features'),
    jsonb_object_keys(attributes)
FROM products;

-- 创建JSON索引
CREATE INDEX idx_attributes ON products USING GIN (attributes);

五、PostgreSQL 索引管理

5.1 创建索引
sql 复制代码
-- B-tree索引(默认)
CREATE INDEX idx_last_name ON employees(last_name);

-- 复合索引
CREATE INDEX idx_name_dept ON employees(last_name, first_name, department_id);

-- 唯一索引
CREATE UNIQUE INDEX uk_email ON employees(email);

-- 部分索引(条件索引)
CREATE INDEX idx_active_employees ON employees(email) 
WHERE status = 'active';

-- 表达式索引
CREATE INDEX idx_lower_email ON employees(LOWER(email));
CREATE INDEX idx_year ON employees(EXTRACT(YEAR FROM hire_date));

-- 覆盖索引(INCLUDE)
CREATE INDEX idx_employee_covering ON employees(department_id, hire_date)
INCLUDE (first_name, last_name, salary);

-- GIN索引(用于数组、JSON、全文搜索)
CREATE INDEX idx_attributes_gin ON products USING GIN (attributes);

-- GiST索引(用于地理空间、范围)
CREATE INDEX idx_location_gist ON places USING GIST (location);

-- BRIN索引(用于大型表的时间范围)
CREATE INDEX idx_sales_date_brin ON sales USING BRIN (sale_date);

-- 并发创建索引(不锁表)
CREATE INDEX CONCURRENTLY idx_employees_department ON employees(department_id);

六、PostgreSQL 事务管理

6.1 事务控制
sql 复制代码
-- 开始事务
BEGIN;
-- 或者
START TRANSACTION;

-- 设置事务特性
BEGIN TRANSACTION 
    ISOLATION LEVEL SERIALIZABLE 
    READ WRITE 
    DEFERRABLE;

-- 保存点
SAVEPOINT my_savepoint;

-- 回滚到保存点
ROLLBACK TO my_savepoint;

-- 释放保存点
RELEASE SAVEPOINT my_savepoint;

-- 提交事务
COMMIT;

-- 回滚事务
ROLLBACK;

-- 完整示例
BEGIN;

INSERT INTO orders (customer_id, amount) VALUES (1, 100.00);
UPDATE accounts SET balance = balance - 100 WHERE customer_id = 1;

-- 检查约束
SAVEPOINT before_check;

-- 可以在这里添加其他操作

COMMIT;
6.2 锁机制
sql 复制代码
-- 行级锁
SELECT * FROM accounts WHERE id = 1 FOR UPDATE;

-- 非阻塞锁
SELECT * FROM accounts WHERE id = 1 FOR UPDATE NOWAIT;

-- 跳过锁定的行
SELECT * FROM accounts WHERE id = 1 FOR UPDATE SKIP LOCKED;

-- 共享锁
SELECT * FROM accounts WHERE id = 1 FOR SHARE;

-- 表级锁
LOCK TABLE accounts IN ACCESS EXCLUSIVE MODE;

-- 查看锁信息
SELECT 
    locktype,
    relation::regclass,
    mode,
    granted
FROM pg_locks
WHERE relation = 'accounts'::regclass;

七、PostgreSQL 函数和存储过程

7.1 函数
sql 复制代码
-- 创建函数
CREATE OR REPLACE FUNCTION get_employee_count(dept_id INTEGER)
RETURNS INTEGER AS $$
DECLARE
    emp_count INTEGER;
BEGIN
    SELECT COUNT(*) INTO emp_count
    FROM employees
    WHERE department_id = dept_id;
    
    RETURN emp_count;
END;
$$ LANGUAGE plpgsql;

-- 调用函数
SELECT get_employee_count(1);

-- 返回表的函数
CREATE OR REPLACE FUNCTION get_employees_by_dept(dept_id INTEGER)
RETURNS TABLE (
    emp_id INTEGER,
    full_name VARCHAR(101),
    salary NUMERIC(10,2)
) AS $$
BEGIN
    RETURN QUERY
    SELECT 
        e.id,
        e.first_name || ' ' || e.last_name,
        e.salary
    FROM employees e
    WHERE e.department_id = dept_id;
END;
$$ LANGUAGE plpgsql;

-- 使用表函数
SELECT * FROM get_employees_by_dept(1);
7.2 存储过程
sql 复制代码
-- 创建存储过程
CREATE OR REPLACE PROCEDURE update_salary(
    emp_id INTEGER,
    increase_percent NUMERIC
)
LANGUAGE plpgsql
AS $$
DECLARE
    old_salary NUMERIC(10,2);
    new_salary NUMERIC(10,2);
BEGIN
    -- 获取当前工资
    SELECT salary INTO old_salary
    FROM employees
    WHERE id = emp_id;
    
    -- 计算新工资
    new_salary := old_salary * (1 + increase_percent / 100);
    
    -- 更新工资
    UPDATE employees
    SET salary = new_salary
    WHERE id = emp_id;
    
    -- 记录日志
    INSERT INTO salary_history 
    (employee_id, old_salary, new_salary, change_date)
    VALUES (emp_id, old_salary, new_salary, NOW());
    
    COMMIT;
EXCEPTION
    WHEN OTHERS THEN
        ROLLBACK;
        RAISE;
END;
$$;

-- 调用存储过程
CALL update_salary(1, 10.0);

Redis 详细教程

一、Redis 基础操作

1.1 连接和配置
bash 复制代码
# 连接Redis
redis-cli

# 指定主机和端口
redis-cli -h localhost -p 6379

# 密码认证
redis-cli -a password

# 连接指定数据库(0-15)
redis-cli -n 1

# 执行命令
redis-cli set key value
redis-cli get key

# 批量执行命令
echo -e "set key1 value1\nget key1" | redis-cli

# 查看配置
redis-cli config get *
redis-cli config get maxmemory
1.2 键操作
redis 复制代码
-- 设置键值
SET user:1:name "张三"
SET user:1:age 25
SET user:1:email "zhangsan@example.com"

-- 获取键值
GET user:1:name

-- 检查键是否存在
EXISTS user:1:name

-- 删除键
DEL user:1:email

-- 设置过期时间
SET session:abc123 "userdata" EX 3600  -- 3600秒后过期
EXPIRE user:1:session 1800  -- 1800秒后过期

-- 查看剩余时间
TTL user:1:session

-- 移除过期时间
PERSIST user:1:session

-- 重命名键
RENAME user:1:name user:1:fullname

-- 随机获取一个键
RANDOMKEY

-- 扫描键(分批处理大量键)
SCAN 0 MATCH "user:*" COUNT 100

二、Redis 数据结构操作

2.1 字符串(String)
redis 复制代码
-- 基本操作
SET counter 100
INCR counter  -- 增加到101
DECR counter  -- 减少到100
INCRBY counter 50  -- 增加50
DECRBY counter 20  -- 减少20

-- 批量操作
MSET key1 "value1" key2 "value2" key3 "value3"
MGET key1 key2 key3

-- 追加操作
APPEND greeting "Hello"
APPEND greeting " World"  -- 变成"Hello World"

-- 获取部分字符串
SET message "Hello Redis"
GETRANGE message 0 4  -- "Hello"
GETRANGE message 6 10  -- "Redis"

-- 设置并获取旧值
GETSET counter 200  -- 返回旧值,设置新值

-- 位操作
SETBIT mykey 7 1  -- 设置第7位为1
GETBIT mykey 7  -- 获取第7位的值
BITCOUNT mykey  -- 统计1的位数
2.2 哈希(Hash)
redis 复制代码
-- 设置哈希字段
HSET user:1000 name "张三"
HSET user:1000 age 30
HSET user:1000 email "zhangsan@example.com"

-- 批量设置
HMSET user:1001 name "李四" age 25 email "lisi@example.com"

-- 获取字段
HGET user:1000 name
HMGET user:1000 name age email

-- 获取所有字段和值
HGETALL user:1000

-- 获取所有字段名
HKEYS user:1000

-- 获取所有值
HVALS user:1000

-- 检查字段是否存在
HEXISTS user:1000 email

-- 删除字段
HDEL user:1000 email

-- 字段自增
HINCRBY user:1000 age 1

-- 字段长度
HLEN user:1000

-- 设置字段(不存在时才设置)
HSETNX user:1000 address "北京"
2.3 列表(List)
redis 复制代码
-- 左侧插入
LPUSH tasks "task1"
LPUSH tasks "task2" "task3"  -- 可以一次插入多个

-- 右侧插入
RPUSH tasks "task4"
RPUSH tasks "task5" "task6"

-- 获取列表长度
LLEN tasks

-- 获取元素
LINDEX tasks 0  -- 获取第一个元素
LINDEX tasks -1  -- 获取最后一个元素

-- 范围获取
LRANGE tasks 0 2  -- 获取前3个元素
LRANGE tasks 0 -1  -- 获取所有元素

-- 弹出元素
LPOP tasks  -- 左侧弹出
RPOP tasks  -- 右侧弹出

-- 阻塞弹出(队列模式)
BLPOP queue 30  -- 阻塞30秒等待元素
BRPOP queue 30

-- 插入元素
LINSERT tasks BEFORE "task2" "newtask"  -- 在task2前插入
LINSERT tasks AFTER "task2" "newtask"   -- 在task2后插入

-- 移除元素
LREM tasks 2 "task1"  -- 从列表移除2个task1
LREM tasks 0 "task1"  -- 移除所有task1

-- 修剪列表
LTRIM tasks 0 4  -- 只保留前5个元素

-- 设置元素
LSET tasks 0 "newtask1"  -- 设置索引0的元素
2.4 集合(Set)
redis 复制代码
-- 添加元素
SADD tags "redis" "database" "nosql"
SADD tags "redis"  -- 重复元素会被忽略

-- 获取所有元素
SMEMBERS tags

-- 检查元素是否存在
SISMEMBER tags "redis"

-- 移除元素
SREM tags "nosql"

-- 随机获取元素
SPOP tags  -- 移除并返回一个随机元素
SRANDMEMBER tags  -- 返回但不移除随机元素
SRANDMEMBER tags 2  -- 返回2个随机元素

-- 集合运算
SADD set1 "a" "b" "c"
SADD set2 "b" "c" "d"

-- 交集
SINTER set1 set2  -- "b" "c"

-- 并集
SUNION set1 set2  -- "a" "b" "c" "d"

-- 差集
SDIFF set1 set2  -- "a"(在set1但不在set2)
SDIFF set2 set1  -- "d"(在set2但不在set1)

-- 集合大小
SCARD tags

-- 移动元素
SMOVE set1 set2 "a"  -- 将a从set1移动到set2
2.5 有序集合(Sorted Set)
redis 复制代码
-- 添加元素(带分数)
ZADD leaderboard 100 "player1"
ZADD leaderboard 200 "player2" 150 "player3"

-- 获取分数
ZSCORE leaderboard "player1"

-- 增加分数
ZINCRBY leaderboard 50 "player1"  -- player1分数变为150

-- 按排名获取
ZRANGE leaderboard 0 -1  -- 获取所有元素(按分数升序)
ZRANGE leaderboard 0 -1 WITHSCORES  -- 带分数
ZREVRANGE leaderboard 0 2 WITHSCORES  -- 降序前3名

-- 按分数范围获取
ZRANGEBYSCORE leaderboard 100 200  -- 分数在100-200之间的元素
ZRANGEBYSCORE leaderboard 100 (200  -- 分数>=100且<200
ZRANGEBYSCORE leaderboard -inf +inf  -- 所有元素

-- 获取排名
ZRANK leaderboard "player1"  -- 升序排名(从0开始)
ZREVRANK leaderboard "player1"  -- 降序排名

-- 获取元素数量
ZCARD leaderboard
ZCOUNT leaderboard 100 200  -- 分数在100-200之间的元素数量

-- 移除元素
ZREM leaderboard "player1"

-- 按排名移除
ZREMRANGEBYRANK leaderboard 0 2  -- 移除排名0-2的元素

-- 按分数移除
ZREMRANGEBYSCORE leaderboard 0 100  -- 移除分数0-100的元素

-- 集合运算
ZADD zset1 1 "a" 2 "b" 3 "c"
ZADD zset2 2 "b" 3 "c" 4 "d"

-- 交集
ZINTERSTORE result 2 zset1 zset2 WEIGHTS 1 1 AGGREGATE SUM

-- 并集
ZUNIONSTORE result 2 zset1 zset2 WEIGHTS 1 1 AGGREGATE SUM

三、Redis 高级功能

3.1 发布订阅
redis 复制代码
-- 订阅频道
SUBSCRIBE news notifications

-- 在另一个客户端发布消息
PUBLISH news "Breaking news!"
PUBLISH notifications "New message received"

-- 模式订阅
PSUBSCRIBE user.*   -- 订阅所有user.开头的频道

-- 取消订阅
UNSUBSCRIBE news
PUNSUBSCRIBE user.*

-- 查看订阅
PUBSUB CHANNELS  -- 查看活跃频道
PUBSUB NUMSUB news notifications  -- 查看订阅者数量
3.2 事务
redis 复制代码
-- 开启事务
MULTI

-- 添加命令到队列
SET balance:1 1000
SET balance:2 2000
INCRBY balance:1 500
DECRBY balance:2 500

-- 执行事务
EXEC

-- 取消事务
MULTI
SET key1 "value1"
DISCARD  -- 取消事务

-- 监视键(乐观锁)
WATCH balance:1 balance:2
MULTI
INCRBY balance:1 100
INCRBY balance:2 -100
EXEC  -- 如果在EXEC前有其他人修改了balance:1或balance:2,事务会失败

UNWATCH  -- 取消监视
3.3 Lua脚本
redis 复制代码
-- 执行简单脚本
EVAL "return {KEYS[1],ARGV[1]}" 1 key1 "hello"

-- 缓存脚本
SCRIPT LOAD "return redis.call('GET', KEYS[1])"
-- 返回: "abcdef123456..." (脚本SHA1)

-- 使用缓存的脚本
EVALSHA abcdef123456... 1 mykey

-- 检查脚本是否存在
SCRIPT EXISTS abcdef123456...

-- 清空脚本缓存
SCRIPT FLUSH

-- 复杂示例:原子性地检查并设置
EVAL "
    local current = redis.call('GET', KEYS[1])
    if current == ARGV[1] then
        redis.call('SET', KEYS[1], ARGV[2])
        return 1
    else
        return 0
    end
" 1 username:lock session_id new_session_id
3.4 管道(Pipeline)
bash 复制代码
# 使用管道批量执行命令
(echo -en "PING\r\nSET key1 value1\r\nGET key1\r\nINCR counter\r\n"; sleep 1) | nc localhost 6379

# 或者使用redis-cli管道模式
echo -e "SET key1 value1\nGET key1" | redis-cli --pipe

四、Redis 持久化和备份

4.1 持久化配置
redis 复制代码
-- 查看持久化配置
CONFIG GET save
CONFIG GET appendonly

-- RDB持久化(快照)
-- 手动保存
SAVE  -- 阻塞保存
BGSAVE  -- 后台保存

-- 查看RDB信息
INFO persistence

-- AOF持久化(追加日志)
-- 开启AOF
CONFIG SET appendonly yes

-- 重写AOF文件
BGREWRITEAOF

-- 同步策略
CONFIG SET appendfsync always  -- 每次写入都同步
CONFIG SET appendfsync everysec  -- 每秒同步(默认)
CONFIG SET appendfsync no  -- 由操作系统决定

-- 混合持久化(RDB+AOF)
CONFIG SET aof-use-rdb-preamble yes
4.2 备份恢复
bash 复制代码
# 备份RDB文件
cp /var/lib/redis/dump.rdb /backup/redis-backup-$(date +%Y%m%d).rdb

# 备份AOF文件
cp /var/lib/redis/appendonly.aof /backup/redis-aof-$(date +%Y%m%d).aof

# 从RDB恢复
# 1. 停止Redis
redis-cli shutdown

# 2. 恢复备份文件
cp /backup/dump.rdb /var/lib/redis/

# 3. 启动Redis
redis-server /etc/redis/redis.conf

# 从AOF恢复
# 1. 复制AOF文件
cp /backup/appendonly.aof /var/lib/redis/

# 2. 启动Redis(会自动加载AOF)

MongoDB 详细教程

一、MongoDB 基础操作

1.1 连接数据库
bash 复制代码
# 连接本地MongoDB
mongosh

# 连接远程MongoDB
mongosh "mongodb://username:password@hostname:27017/database"

# 连接复制集
mongosh "mongodb://host1:27017,host2:27017,host3:27017/?replicaSet=rs0"

# 连接MongoDB Atlas
mongosh "mongodb+srv://cluster0.mongodb.net/database" --apiVersion 1 --username username

# 指定认证数据库
mongosh -u username -p password --authenticationDatabase admin

# 执行JavaScript文件
mongosh --quiet script.js
1.2 数据库操作
javascript 复制代码
// 查看所有数据库
show dbs

// 查看当前数据库
db

// 创建/切换数据库
use company

// 查看数据库状态
db.stats()

// 查看数据库信息
db.runCommand({dbStats: 1})

// 删除数据库(需要先切换到该数据库)
use old_database
db.dropDatabase()

二、MongoDB 集合操作

2.1 创建和查看集合
javascript 复制代码
// 创建集合
db.createCollection("employees")
db.createCollection("logs", {
    capped: true,
    size: 1000000,
    max: 1000
})

// 查看所有集合
show collections

// 查看集合信息
db.employees.stats()
db.getCollectionInfos()

// 重命名集合
db.employees.renameCollection("staff")

// 删除集合
db.employees.drop()
2.2 索引管理
javascript 复制代码
// 创建索引
db.employees.createIndex({ email: 1 })  // 升序索引
db.employees.createIndex({ email: 1 }, { unique: true })  // 唯一索引
db.employees.createIndex({ last_name: 1, first_name: 1 })  // 复合索引

// 创建文本索引
db.articles.createIndex(
    { title: "text", content: "text" },
    { weights: { title: 10, content: 5 } }
)

// 创建地理空间索引
db.places.createIndex({ location: "2dsphere" })

// 创建TTL索引(自动过期)
db.sessions.createIndex(
    { created_at: 1 },
    { expireAfterSeconds: 3600 }  // 1小时后自动删除
)

// 查看索引
db.employees.getIndexes()

// 删除索引
db.employees.dropIndex("email_1")
db.employees.dropIndexes()  // 删除所有索引(除了_id)

三、MongoDB CRUD 操作

3.1 插入文档
javascript 复制代码
// 插入单个文档
db.employees.insertOne({
    first_name: "张",
    last_name: "三",
    email: "zhangsan@example.com",
    age: 30,
    department: "技术部",
    skills: ["Java", "Python", "MongoDB"],
    address: {
        city: "北京",
        street: "中关村大街"
    },
    hire_date: new Date("2020-01-15"),
    salary: 8000
})

// 插入多个文档
db.employees.insertMany([
    {
        first_name: "李",
        last_name: "四",
        email: "lisi@example.com",
        age: 25,
        department: "市场部",
        salary: 6000
    },
    {
        first_name: "王",
        last_name: "五",
        email: "wangwu@example.com",
        age: 28,
        department: "技术部",
        salary: 7500
    }
])

// 插入并返回文档
const result = db.employees.insertOne({
    first_name: "赵",
    last_name: "六",
    email: "zhaoliu@example.com",
    salary: 9000
})
print("插入的ID:", result.insertedId)
3.2 查询文档
javascript 复制代码
// 查询所有文档
db.employees.find()

// 格式化输出
db.employees.find().pretty()

// 条件查询
db.employees.find({ department: "技术部" })
db.employees.find({ age: { $gt: 25 } })  // 年龄大于25
db.employees.find({ age: { $gte: 25, $lte: 35 } })  // 年龄25-35
db.employees.find({ department: { $in: ["技术部", "市场部"] } })
db.employees.find({ department: { $nin: ["人事部"] } })

// 复合条件查询
db.employees.find({
    department: "技术部",
    salary: { $gt: 7000 }
})

// OR查询
db.employees.find({
    $or: [
        { department: "技术部" },
        { salary: { $gt: 8000 } }
    ]
})

// 嵌套文档查询
db.employees.find({ "address.city": "北京" })

// 数组查询
db.employees.find({ skills: "Java" })  // 包含Java技能
db.employees.find({ skills: { $all: ["Java", "Python"] } })  // 同时包含
db.employees.find({ skills: { $size: 3 } })  // 有3个技能

// 正则表达式查询
db.employees.find({ email: /@example\.com$/ })
db.employees.find({ last_name: /^张/ })  // 姓氏以张开头的

// 投影(选择字段)
db.employees.find(
    { department: "技术部" },
    { first_name: 1, last_name: 1, email: 1, _id: 0 }
)

// 排除字段
db.employees.find(
    {},
    { skills: 0, address: 0 }
)

// 分页查询
db.employees.find().skip(20).limit(10)  // 第3页,每页10条

// 排序
db.employees.find().sort({ salary: -1 })  // 按工资降序
db.employees.find().sort({ department: 1, salary: -1 })  // 部门升序,工资降序

// 计数
db.employees.countDocuments({ department: "技术部" })
db.employees.estimatedDocumentCount()  // 估算总数(更快)

// 去重
db.employees.distinct("department")
3.3 更新文档
javascript 复制代码
// 更新单个文档
db.employees.updateOne(
    { email: "zhangsan@example.com" },
    { $set: { salary: 8500 } }
)

// 更新多个文档
db.employees.updateMany(
    { department: "技术部" },
    { $set: { salary: 9000 } }
)

// 替换整个文档
db.employees.replaceOne(
    { email: "zhangsan@example.com" },
    {
        first_name: "张",
        last_name: "三",
        email: "zhangsan@example.com",
        salary: 9000,
        updated_at: new Date()
    }
)

// 更新操作符
db.employees.updateOne(
    { email: "zhangsan@example.com" },
    {
        $set: { salary: 9000 },  // 设置字段
        $inc: { age: 1 },  // 增加字段值
        $push: { skills: "Go" },  // 添加到数组
        $pull: { skills: "PHP" },  // 从数组移除
        $addToSet: { skills: "Docker" },  // 添加到数组(不重复)
        $rename: { "address.city": "city" },  // 重命名字段
        $unset: { temp_field: "" },  // 删除字段
        $currentDate: { updated_at: true }  // 设置当前时间
    }
)

// 数组更新操作符
db.employees.updateOne(
    { email: "zhangsan@example.com" },
    {
        $push: {
            skills: {
                $each: ["Go", "Rust"],  // 添加多个元素
                $position: 0,  // 插入到数组开头
                $sort: 1,  // 数组排序
                $slice: 5  // 只保留前5个元素
            }
        }
    }
)

// 查找并更新(原子操作)
const result = db.employees.findOneAndUpdate(
    { email: "zhangsan@example.com" },
    { $inc: { salary: 500 } },
    {
        returnDocument: "after",  // 返回更新后的文档
        upsert: true  // 如果不存在则插入
    }
)
3.4 删除文档
javascript 复制代码
// 删除单个文档
db.employees.deleteOne({ email: "zhangsan@example.com" })

// 删除多个文档
db.employees.deleteMany({ department: "人事部" })

// 查找并删除
const result = db.employees.findOneAndDelete(
    { email: "zhangsan@example.com" }
)

// 删除所有文档(清空集合)
db.employees.deleteMany({})

// 使用remove(已弃用,建议使用deleteOne/deleteMany)
db.employees.remove({ department: "人事部" })

四、MongoDB 聚合管道

4.1 基本聚合
javascript 复制代码
// 简单聚合
db.employees.aggregate([
    // 阶段1:筛选
    { $match: { department: "技术部" } },
    
    // 阶段2:分组
    { $group: {
        _id: "$department",
        total_employees: { $sum: 1 },
        avg_salary: { $avg: "$salary" },
        max_salary: { $max: "$salary" },
        min_salary: { $min: "$salary" },
        total_salary: { $sum: "$salary" }
    }},
    
    // 阶段3:排序
    { $sort: { avg_salary: -1 } },
    
    // 阶段4:限制
    { $limit: 10 }
])

// 多字段分组
db.employees.aggregate([
    { $group: {
        _id: {
            department: "$department",
            city: "$address.city"
        },
        count: { $sum: 1 }
    }}
])

// 展开数组
db.employees.aggregate([
    { $match: { skills: { $exists: true } } },
    { $unwind: "$skills" },  // 每个技能变成一个文档
    { $group: {
        _id: "$skills",
        count: { $sum: 1 }
    }},
    { $sort: { count: -1 } }
])
4.2 高级聚合
javascript 复制代码
// 多集合关联查询
db.orders.aggregate([
    // 筛选订单
    { $match: { status: "completed" } },
    
    // 关联用户表
    { $lookup: {
        from: "users",
        localField: "user_id",
        foreignField: "_id",
        as: "user_info"
    }},
    
    // 展开关联结果(一对一关系)
    { $unwind: "$user_info" },
    
    // 关联产品表(一对多关系)
    { $lookup: {
        from: "products",
        localField: "product_ids",
        foreignField: "_id",
        as: "products"
    }},
    
    // 分组统计
    { $group: {
        _id: "$user_info.city",
        total_orders: { $sum: 1 },
        total_amount: { $sum: "$amount" },
        avg_amount: { $avg: "$amount" }
    }},
    
    // 筛选分组结果
    { $match: { total_orders: { $gt: 5 } } },
    
    // 排序
    { $sort: { total_amount: -1 } },
    
    // 输出到集合
    { $out: "city_sales_stats" }
])

// 条件聚合
db.employees.aggregate([
    { $project: {
        name: { $concat: ["$first_name", " ", "$last_name"] },
        salary: 1,
        salary_grade: {
            $switch: {
                branches: [
                    { case: { $gte: ["$salary", 10000] }, then: "A" },
                    { case: { $gte: ["$salary", 7000] }, then: "B" },
                    { case: { $gte: ["$salary", 5000] }, then: "C" }
                ],
                default: "D"
            }
        }
    }}
])

// 日期聚合
db.orders.aggregate([
    { $project: {
        year: { $year: "$order_date" },
        month: { $month: "$order_date" },
        week: { $week: "$order_date" },
        dayOfWeek: { $dayOfWeek: "$order_date" },
        amount: 1
    }},
    { $group: {
        _id: { year: "$year", month: "$month" },
        total_amount: { $sum: "$amount" },
        order_count: { $sum: 1 }
    }},
    { $sort: { "_id.year": 1, "_id.month": 1 } }
])

五、MongoDB 高级功能

5.1 地理空间查询
javascript 复制代码
// 创建地理空间索引
db.places.createIndex({ location: "2dsphere" })

// 插入地理空间数据
db.places.insertMany([
    {
        name: "天安门",
        category: "景点",
        location: {
            type: "Point",
            coordinates: [116.3974, 39.9093]  // [经度, 纬度]
        }
    },
    {
        name: "故宫",
        category: "景点",
        location: {
            type: "Point",
            coordinates: [116.3972, 39.9163]
        }
    }
])

// 附近查询(10公里内)
db.places.find({
    location: {
        $near: {
            $geometry: {
                type: "Point",
                coordinates: [116.3974, 39.9093]
            },
            $maxDistance: 10000  // 10公里
        }
    }
})

// 多边形区域查询
db.places.find({
    location: {
        $geoWithin: {
            $geometry: {
                type: "Polygon",
                coordinates: [[
                    [116.38, 39.90],
                    [116.41, 39.90],
                    [116.41, 39.92],
                    [116.38, 39.92],
                    [116.38, 39.90]
                ]]
            }
        }
    }
})

// 距离计算
db.places.aggregate([
    {
        $geoNear: {
            near: { type: "Point", coordinates: [116.3974, 39.9093] },
            distanceField: "distance",
            maxDistance: 5000,
            spherical: true
        }
    },
    { $sort: { distance: 1 } }
])
5.2 文本搜索
javascript 复制代码
// 创建文本索引
db.articles.createIndex(
    { title: "text", content: "text" },
    { 
        weights: { title: 10, content: 5 },
        default_language: "english"
    }
)

// 文本搜索
db.articles.find(
    { $text: { $search: "database mongodb" } }
)

// 短语搜索
db.articles.find(
    { $text: { $search: "\"mongodb database\"" } }
)

// 排除词
db.articles.find(
    { $text: { $search: "mongodb -sql" } }  // 包含mongodb但不包含sql
)

// 文本搜索排序
db.articles.find(
    { $text: { $search: "database" } },
    { score: { $meta: "textScore" } }
).sort({ score: { $meta: "textScore" } })
5.3 事务管理
javascript 复制代码
// MongoDB 4.0+ 支持多文档事务
const session = db.getMongo().startSession();
session.startTransaction({
    readConcern: { level: "snapshot" },
    writeConcern: { w: "majority" }
});

try {
    const users = session.getDatabase("company").users;
    const accounts = session.getDatabase("company").accounts;
    
    // 在事务中执行多个操作
    users.insertOne({
        _id: 1001,
        name: "张三",
        email: "zhangsan@example.com"
    });
    
    accounts.insertOne({
        user_id: 1001,
        balance: 1000,
        created_at: new Date()
    });
    
    // 提交事务
    session.commitTransaction();
    console.log("事务提交成功");
} catch (error) {
    console.log("事务失败,回滚:", error);
    session.abortTransaction();
} finally {
    session.endSession();
}

六、MongoDB 性能优化

6.1 查询优化
javascript 复制代码
// 使用投影减少返回数据
db.employees.find({}, { first_name: 1, last_name: 1 })

// 使用覆盖查询(索引包含所有查询字段)
db.employees.createIndex({ department: 1, salary: 1 })
db.employees.find(
    { department: "技术部", salary: { $gt: 7000 } },
    { _id: 0, department: 1, salary: 1 }
)  // 这个查询可以从索引中获取所有数据,不需要访问文档

// 使用索引排序
db.employees.find().sort({ salary: 1 })  // 需要有salary索引

// 避免全表扫描
db.employees.find({ email: /^zhang/ })  // 可以走索引
db.employees.find({ email: /zhang/ })  // 不能走索引

// 使用hint强制使用索引
db.employees.find({ department: "技术部" }).hint({ department: 1 })

// 监控查询性能
db.employees.find({ salary: { $gt: 7000 } }).explain("executionStats")

// 设置查询超时
db.employees.find({ department: "技术部" }).maxTimeMS(1000)
6.2 批量操作
javascript 复制代码
// 批量插入
const bulk = db.employees.initializeUnorderedBulkOp();
for (let i = 0; i < 1000; i++) {
    bulk.insert({
        first_name: "User",
        last_name: i.toString(),
        email: `user${i}@example.com`,
        salary: Math.floor(Math.random() * 5000) + 3000
    });
}
bulk.execute();

// 批量更新
const bulk = db.employees.initializeUnorderedBulkOp();
bulk.find({ department: "技术部" }).update({ $set: { salary: 9000 } });
bulk.find({ department: "市场部" }).update({ $inc: { salary: 500 } });
bulk.execute();

// 批量操作选项
db.employees.bulkWrite([
    { insertOne: { document: { name: "张三" } } },
    { updateOne: {
        filter: { name: "李四" },
        update: { $set: { salary: 8000 } }
    }},
    { deleteOne: { filter: { name: "王五" } } }
], {
    ordered: false,  // 无序执行(更快)
    writeConcern: { w: 1 }
})

附录:常见错误和解决方案

MySQL 常见问题

sql 复制代码
-- 1. 连接数过多
SHOW PROCESSLIST;
SHOW VARIABLES LIKE 'max_connections';
SET GLOBAL max_connections = 1000;

-- 2. 慢查询
SHOW VARIABLES LIKE 'slow_query_log';
SHOW VARIABLES LIKE 'long_query_time';
SET GLOBAL slow_query_log = 1;
SET GLOBAL long_query_time = 2;

-- 3. 死锁处理
SHOW ENGINE INNODB STATUS;
SELECT * FROM information_schema.innodb_locks;
SELECT * FROM information_schema.innodb_lock_waits;

-- 4. 表损坏修复
CHECK TABLE table_name;
REPAIR TABLE table_name;
ALTER TABLE table_name ENGINE=InnoDB;

-- 5. 内存不足
SHOW VARIABLES LIKE 'innodb_buffer_pool_size';
SET GLOBAL innodb_buffer_pool_size = 4294967296;  -- 4GB

PostgreSQL 常见问题

sql 复制代码
-- 1. 连接数过多
SELECT count(*) FROM pg_stat_activity;
SELECT max_conn FROM pg_settings WHERE name = 'max_connections';
ALTER SYSTEM SET max_connections = 200;

-- 2. 死锁
SELECT * FROM pg_locks WHERE granted = false;
SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE state = 'idle';

-- 3. 表膨胀
VACUUM FULL table_name;
REINDEX TABLE table_name;

-- 4. WAL日志过大
SELECT * FROM pg_stat_archiver;
ALTER SYSTEM SET wal_keep_segments = 64;

-- 5. 查询慢
EXPLAIN (ANALYZE, BUFFERS) SELECT * FROM table_name;
SELECT * FROM pg_stat_statements ORDER BY total_time DESC LIMIT 10;

Redis 常见问题

redis 复制代码
-- 1. 内存使用过高
INFO memory
CONFIG SET maxmemory 2gb
CONFIG SET maxmemory-policy allkeys-lru

-- 2. 慢查询
SLOWLOG GET 10
CONFIG SET slowlog-log-slower-than 10000

-- 3. AOF文件过大
BGREWRITEAOF
CONFIG SET auto-aof-rewrite-percentage 100
CONFIG SET auto-aof-rewrite-min-size 64mb

-- 4. 主从同步延迟
INFO replication
CONFIG SET repl-backlog-size 100mb

-- 5. 键过多
SCAN 0 COUNT 100
CONFIG SET databases 16

MongoDB 常见问题

javascript 复制代码
// 1. 连接数过多
db.serverStatus().connections
db.adminCommand({setParameter: 1, maxConnections: 1000})

// 2. 内存使用高
db.serverStatus().mem
db.adminCommand({setParameter: 1, wiredTigerEngineRuntimeConfig: "cache_size=4G"})

// 3. 查询慢
db.setProfilingLevel(1, 100)
db.system.profile.find().sort({ts: -1}).limit(10)

// 4. 索引缺失
db.collection.getIndexes()
db.collection.createIndex({field: 1})

// 5. 分片不均
db.adminCommand({flushRouterConfig: 1})
db.adminCommand({moveChunk: "db.collection", find: {_id: ObjectId()}, to: "shard2"})
相关推荐
01_ice3 小时前
MySQL事务
数据库·mysql
玛丽莲茼蒿4 小时前
Redis(六)—— Redis高级
数据库·redis·缓存
渣渣盟4 小时前
Flink 写入 Redis 实战:数据模型选型、连接池调优与常见坑
大数据·redis·flink
陈聪.5 小时前
企业级 NoSQL 数据库 Redis 核心知识整理
数据库·redis·nosql
隔窗听雨眠7 小时前
MySQL索引机制深度解析:从B+树原理到高并发查询优化的完整指南
数据库·b树·mysql
我的xiaodoujiao7 小时前
使用PyMySQL模块技术操作MySQL数据库
数据库·python·测试工具·mysql
To_OC15 小时前
Next.js + Redis 构建笔记系统:Redis Hash 实战与性能优化
redis·后端·next.js
灯澜忆梦18 小时前
【MySQL17】进阶篇 | InnoDB引擎
数据库·mysql
lv__pf19 小时前
redis【msb 2026金三银四redis上】
数据库·redis·缓存