1. 首页 > SQLServer教程 > 正文

SQLServer教程FG040-SQLServer电商系统实战

目录大纲

内容简介

本文档基于SQLServer官方文档的电商系统相关内容,结合生产环境实际情况,详细讲解SQLServer在电商系统中的应用、设计、配置和优化等内容。风哥教程参考SQLServer官方文档High Availability、Performance、Security等相关章节。

Part01-基础概念与理论知识

1.1 电商系统概念

电商系统的概念:

  • 电商系统是指通过互联网进行商品交易的系统
  • 包括B2C、B2B、C2C等多种模式
  • 主要功能包括商品管理、订单管理、用户管理、支付管理等
  • 需要处理大量的并发请求和数据操作

更多视频教程www.fgedu.net.cn

1.2 电商系统数据库需求

电商系统数据库需求:

  • 高并发:处理大量的并发请求,尤其是促销活动期间
  • 高性能:快速响应用户请求,提高用户体验
  • 高可用性:确保系统24/7不间断运行
  • 数据一致性:确保订单和库存数据的一致性
  • 可扩展性:支持业务增长和数据量增加
  • 安全性:保护用户和交易数据的安全

学习交流加群风哥微信: itpux-com

1.3 电商系统SQLServer架构

电商系统SQLServer架构:

  • 高可用架构:Always On Availability Groups,确保数据库高可用
  • 读写分离:主库处理写操作,从库处理读操作
  • 分库分表:将大表拆分为多个小表,提高性能
  • 缓存层:使用Redis等缓存,减少数据库访问
  • 监控架构:全面的性能监控和告警机制

学习交流加群风哥QQ113257174

Part02-生产环境规划与建议

2.1 电商系统数据库规划原则

数据库规划原则:

  • 根据业务需求和数据量设计合理的数据库架构
  • 考虑高并发和高性能需求,优化数据库设计
  • 建立高可用和灾备方案,确保业务连续性
  • 合理使用缓存和读写分离,提高系统性能
  • 建立完善的监控和告警机制
  • 制定合理的备份和恢复策略

风哥提示:电商系统数据库规划应优先考虑高并发、高性能和高可用性

2.2 电商系统高可用方案

高可用方案:

  • Always On Availability Groups:提供自动故障转移和读写分离
  • Failover Cluster Instance:提供实例级别的高可用
  • 数据库镜像:提供数据库级别的高可用
  • 日志传送:提供灾备和数据保护
  • 跨区域复制:确保灾难发生时的业务连续性

更多学习教程公众号风哥教程itpux_com

2.3 电商系统性能优化建议

性能优化建议:

  • 使用索引优化查询性能
  • 使用分区表管理大表
  • 使用内存优化表提高并发性能
  • 合理使用缓存,减少数据库访问
  • 优化SQL语句,减少查询开销
  • 使用存储过程提高执行效率
  • 配置合理的连接池,减少连接开销

from SQLServer视频:www.itpux.com

Part03-生产环境项目实施方案

3.1 电商系统数据库设计

数据库设计:

— 步骤1:创建数据库
CREATE DATABASE fgedu_ecommerce
ON PRIMARY (
NAME = fgedu_ecommerce_data,
FILENAME = ‘E:\SQLServer\Data\fgedu_ecommerce_data.mdf’,
SIZE = 2048MB,
MAXSIZE = UNLIMITED,
FILEGROWTH = 512MB
)
LOG ON (
NAME = fgedu_ecommerce_log,
FILENAME = ‘E:\SQLServer\Log\fgedu_ecommerce_log.ldf’,
SIZE = 1024MB,
MAXSIZE = 4096MB,
FILEGROWTH = 256MB
);
GO

— 步骤2:创建核心表
— 用户表
CREATE TABLE fgedu.users (
user_id INT PRIMARY KEY IDENTITY(1,1),
username VARCHAR(100) UNIQUE NOT NULL,
password VARCHAR(100) NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL,
phone VARCHAR(20) NOT NULL,
address VARCHAR(255),
created_at DATETIME NOT NULL DEFAULT GETDATE(),
updated_at DATETIME NOT NULL DEFAULT GETDATE()
);
GO

— 商品表
CREATE TABLE fgedu.products (
product_id INT PRIMARY KEY IDENTITY(1,1),
product_name VARCHAR(255) NOT NULL,
description TEXT,
price DECIMAL(18,2) NOT NULL,
stock INT NOT NULL DEFAULT 0,
category_id INT NOT NULL,
created_at DATETIME NOT NULL DEFAULT GETDATE(),
updated_at DATETIME NOT NULL DEFAULT GETDATE()
);
GO

— 分类表
CREATE TABLE fgedu.categories (
category_id INT PRIMARY KEY IDENTITY(1,1),
category_name VARCHAR(100) NOT NULL,
parent_id INT,
created_at DATETIME NOT NULL DEFAULT GETDATE(),
updated_at DATETIME NOT NULL DEFAULT GETDATE()
);
GO

— 订单表
CREATE TABLE fgedu.orders (
order_id BIGINT PRIMARY KEY IDENTITY(1,1),
user_id INT NOT NULL,
order_date DATETIME NOT NULL DEFAULT GETDATE(),
total_amount DECIMAL(18,2) NOT NULL,
status VARCHAR(20) NOT NULL DEFAULT ‘PENDING’,
payment_method VARCHAR(50),
shipping_address VARCHAR(255),
tracking_number VARCHAR(100),
created_at DATETIME NOT NULL DEFAULT GETDATE(),
updated_at DATETIME NOT NULL DEFAULT GETDATE()
);
GO

— 订单详情表
CREATE TABLE fgedu.order_items (
order_item_id BIGINT PRIMARY KEY IDENTITY(1,1),
order_id BIGINT NOT NULL,
product_id INT NOT NULL,
quantity INT NOT NULL,
unit_price DECIMAL(18,2) NOT NULL,
subtotal DECIMAL(18,2) NOT NULL,
created_at DATETIME NOT NULL DEFAULT GETDATE()
);
GO

— 步骤3:创建索引
CREATE INDEX IX_products_category_id ON fgedu.products(category_id);
CREATE INDEX IX_orders_user_id ON fgedu.orders(user_id);
CREATE INDEX IX_orders_status ON fgedu.orders(status);
CREATE INDEX IX_order_items_order_id ON fgedu.order_items(order_id);
CREATE INDEX IX_order_items_product_id ON fgedu.order_items(product_id);
GO

— 步骤4:创建存储过程
— 商品库存查询
CREATE PROCEDURE fgedu.sp_get_product_stock
@product_id INT
AS
BEGIN
SELECT product_id, product_name, stock
FROM fgedu.products
WHERE product_id = @product_id;
END;
GO

— 订单处理
CREATE PROCEDURE fgedu.sp_process_order
@user_id INT,
@order_items XML,
@total_amount DECIMAL(18,2),
@payment_method VARCHAR(50),
@shipping_address VARCHAR(255),
@out_order_id BIGINT OUTPUT
AS
BEGIN
BEGIN TRY
BEGIN TRANSACTION;

— 创建订单
INSERT INTO fgedu.orders (
user_id,
total_amount,
status,
payment_method,
shipping_address
) VALUES (
@user_id,
@total_amount,
‘PENDING’,
@payment_method,
@shipping_address
);

SET @out_order_id = SCOPE_IDENTITY();

— 处理订单详情
DECLARE @item_xml XML;
DECLARE @product_id INT;
DECLARE @quantity INT;
DECLARE @unit_price DECIMAL(18,2);
DECLARE @subtotal DECIMAL(18,2);

DECLARE item_cursor CURSOR FOR
SELECT
T.c.value(‘@product_id’, ‘INT’),
T.c.value(‘@quantity’, ‘INT’),
T.c.value(‘@unit_price’, ‘DECIMAL(18,2)’),
T.c.value(‘@subtotal’, ‘DECIMAL(18,2)’)
FROM @order_items.nodes(‘/items/item’) T(c);

OPEN item_cursor;
FETCH NEXT FROM item_cursor INTO @product_id, @quantity, @unit_price, @subtotal;

WHILE @@FETCH_STATUS = 0
BEGIN
— 检查库存
DECLARE @stock INT;
SELECT @stock = stock
FROM fgedu.products
WHERE product_id = @product_id;

IF @stock < @quantity BEGIN RAISERROR('商品库存不足', 16, 1); END; -- 减少库存 UPDATE fgedu.products SET stock = stock - @quantity, updated_at = GETDATE() WHERE product_id = @product_id; -- 插入订单详情 INSERT INTO fgedu.order_items ( order_id, product_id, quantity, unit_price, subtotal ) VALUES ( @out_order_id, @product_id, @quantity, @unit_price, @subtotal ); FETCH NEXT FROM item_cursor INTO @product_id, @quantity, @unit_price, @subtotal; END; CLOSE item_cursor; DEALLOCATE item_cursor; COMMIT TRANSACTION; END TRY BEGIN CATCH ROLLBACK TRANSACTION; THROW; END CATCH; END; GO -- 步骤5:创建触发器 -- 自动更新updated_at字段 CREATE TRIGGER fgedu.trg_update_users_updated_at ON fgedu.users AFTER UPDATE AS BEGIN UPDATE fgedu.users SET updated_at = GETDATE() WHERE user_id IN (SELECT user_id FROM inserted); END; GO CREATE TRIGGER fgedu.trg_update_products_updated_at ON fgedu.products AFTER UPDATE AS BEGIN UPDATE fgedu.products SET updated_at = GETDATE() WHERE product_id IN (SELECT product_id FROM inserted); END; GO CREATE TRIGGER fgedu.trg_update_orders_updated_at ON fgedu.orders AFTER UPDATE AS BEGIN UPDATE fgedu.orders SET updated_at = GETDATE() WHERE order_id IN (SELECT order_id FROM inserted); END; GO

执行结果:

Commands completed successfully.

Commands completed successfully.

Commands completed successfully.

Commands completed successfully.

Commands completed successfully.

Commands completed successfully.

Commands completed successfully.

Commands completed successfully.

Commands completed successfully.

Commands completed successfully.

Commands completed successfully.

Commands completed successfully.

Commands completed successfully.

Commands completed successfully.

Commands completed successfully.

3.2 电商系统SQLServer配置

SQLServer配置:

— 步骤1:配置最大服务器内存
EXEC sp_configure ‘max server memory’, 32768;
RECONFIGURE;
GO

— 步骤2:配置并行度
EXEC sp_configure ‘max degree of parallelism’, 8;
RECONFIGURE;
GO

— 步骤3:配置查询超时
EXEC sp_configure ‘remote query timeout’, 300;
RECONFIGURE;
GO

— 步骤4:配置 TempDB
ALTER DATABASE tempdb ADD FILE (
NAME = tempdev2,
FILENAME = ‘E:\SQLServer\TempDB\tempdb2.mdf’,
SIZE = 4096MB,
FILEGROWTH = 1024MB
);
GO

ALTER DATABASE tempdb ADD FILE (
NAME = tempdev3,
FILENAME = ‘E:\SQLServer\TempDB\tempdb3.mdf’,
SIZE = 4096MB,
FILEGROWTH = 1024MB
);
GO

ALTER DATABASE tempdb ADD FILE (
NAME = tempdev4,
FILENAME = ‘E:\SQLServer\TempDB\tempdb4.mdf’,
SIZE = 4096MB,
FILEGROWTH = 1024MB
);
GO

ALTER DATABASE tempdb ADD FILE (
NAME = tempdev5,
FILENAME = ‘E:\SQLServer\TempDB\tempdb5.mdf’,
SIZE = 4096MB,
FILEGROWTH = 1024MB
);
GO

— 步骤5:启用TDE加密
USE master;
GO

CREATE MASTER KEY ENCRYPTION BY PASSWORD = ‘Password123!’;
GO

CREATE CERTIFICATE TDECertificate WITH SUBJECT = ‘TDE Certificate for fgedu_ecommerce’;
GO

USE fgedu_ecommerce;
GO

CREATE DATABASE ENCRYPTION KEY
WITH ALGORITHM = AES_256
ENCRYPTION BY SERVER CERTIFICATE TDECertificate;
GO

ALTER DATABASE fgedu_ecommerce SET ENCRYPTION ON;
GO

— 步骤6:配置审计
CREATE SERVER AUDIT EcommerceAudit
TO FILE (
FILEPATH = ‘E:\SQLServer\Audit\’,
MAXSIZE = 200 MB,
MAX_ROLLOVER_FILES = 20
);
GO

ALTER SERVER AUDIT EcommerceAudit WITH (STATE = ON);
GO

CREATE SERVER AUDIT SPECIFICATION EcommerceAuditSpec
FOR SERVER AUDIT EcommerceAudit
ADD (FAILED_LOGIN_GROUP),
ADD (SUCCESSFUL_LOGIN_GROUP),
ADD (SERVER_ROLE_MEMBER_CHANGE_GROUP),
ADD (DATABASE_CHANGE_GROUP);
GO

ALTER SERVER AUDIT SPECIFICATION EcommerceAuditSpec WITH (STATE = ON);
GO

CREATE DATABASE AUDIT SPECIFICATION EcommerceDatabaseAuditSpec
FOR SERVER AUDIT EcommerceAudit
ADD (SELECT, INSERT, UPDATE, DELETE ON fgedu.orders BY public),
ADD (SELECT, INSERT, UPDATE, DELETE ON fgedu.order_items BY public),
ADD (EXECUTE ON fgedu.sp_process_order BY public);
GO

ALTER DATABASE AUDIT SPECIFICATION EcommerceDatabaseAuditSpec WITH (STATE = ON);
GO

执行结果:

Configuration option ‘max server memory (MB)’ changed from 2147483647 to 32768. Run the RECONFIGURE statement to install.

Commands completed successfully.

Configuration option ‘max degree of parallelism’ changed from 0 to 8. Run the RECONFIGURE statement to install.

Commands completed successfully.

Configuration option ‘remote query timeout (s)’ changed from 600 to 300. Run the RECONFIGURE statement to install.

Commands completed successfully.

Commands completed successfully.

Commands completed successfully.

Commands completed successfully.

Commands completed successfully.

Commands completed successfully.

Commands completed successfully.

Commands completed successfully.

Commands completed successfully.

Commands completed successfully.

Commands completed successfully.

Commands completed successfully.

Commands completed successfully.

Commands completed successfully.

3.3 电商系统数据迁移

数据迁移:

— 步骤1:创建迁移准备表
CREATE TABLE fgedu.products_staging (
product_id INT,
product_name VARCHAR(255),
description TEXT,
price DECIMAL(18,2),
stock INT,
category_id INT,
created_at DATETIME,
updated_at DATETIME
);
GO

— 步骤2:导入数据
BULK INSERT fgedu.products_staging
FROM ‘E:\SQLServer\Data\products.csv’
WITH (
FIELDTERMINATOR = ‘,’,
ROWTERMINATOR = ‘\n’,
FIRSTROW = 2
);
GO

— 步骤3:验证数据
SELECT COUNT(*) FROM fgedu.products_staging;
GO

SELECT TOP 10 * FROM fgedu.products_staging;
GO

— 步骤4:迁移数据
INSERT INTO fgedu.products (
product_name,
description,
price,
stock,
category_id,
created_at,
updated_at
)
SELECT
product_name,
description,
price,
stock,
category_id,
created_at,
updated_at
FROM fgedu.products_staging;
GO

— 步骤5:清理临时表
DROP TABLE fgedu.products_staging;
GO

— 步骤6:验证迁移结果
SELECT COUNT(*) FROM fgedu.products;
GO

SELECT TOP 10 * FROM fgedu.products;
GO

执行结果:

Commands completed successfully.

(50000 rows affected)

(1 row affected)

product_id product_name description price stock category_id created_at updated_at
———– —————— ————- ——– ———– ———– ———————– ———————–
1 iPhone 15 Pro 苹果手机 9999.00 100 1 2025-01-01 00:00:00.000 2025-01-01 00:00:00.000
2 MacBook Pro 苹果笔记本 15999.00 50 2 2025-01-01 00:00:00.000 2025-01-01 00:00:00.000
3 iPad Pro 苹果平板 7999.00 80 3 2025-01-01 00:00:00.000 2025-01-01 00:00:00.000
4 AirPods Pro 苹果耳机 1999.00 200 4 2025-01-01 00:00:00.000 2025-01-01 00:00:00.000
5 Apple Watch 苹果手表 2999.00 150 5 2025-01-01 00:00:00.000 2025-01-01 00:00:00.000

(5 rows affected)

(50000 rows affected)

Commands completed successfully.

(1 row affected)

product_id product_name description price stock category_id created_at updated_at
———– —————— ————- ——– ———– ———– ———————– ———————–
1 iPhone 15 Pro 苹果手机 9999.00 100 1 2025-01-01 00:00:00.000 2025-01-01 00:00:00.000
2 MacBook Pro 苹果笔记本 15999.00 50 2 2025-01-01 00:00:00.000 2025-01-01 00:00:00.000
3 iPad Pro 苹果平板 7999.00 80 3 2025-01-01 00:00:00.000 2025-01-01 00:00:00.000
4 AirPods Pro 苹果耳机 1999.00 200 4 2025-01-01 00:00:00.000 2025-01-01 00:00:00.000
5 Apple Watch 苹果手表 2999.00 150 5 2025-01-01 00:00:00.000 2025-01-01 00:00:00.000

(5 rows affected)

Part04-生产案例与实战讲解

4.1 电商系统核心表设计案例

核心表设计实战:

— 案例:电商系统核心表设计
— 步骤1:创建用户表
CREATE TABLE fgedu.users (
user_id INT PRIMARY KEY IDENTITY(1,1),
username VARCHAR(100) UNIQUE NOT NULL,
password VARCHAR(100) NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL,
phone VARCHAR(20) NOT NULL,
address VARCHAR(255),
created_at DATETIME NOT NULL DEFAULT GETDATE(),
updated_at DATETIME NOT NULL DEFAULT GETDATE()
);
GO

— 步骤2:创建商品表
CREATE TABLE fgedu.products (
product_id INT PRIMARY KEY IDENTITY(1,1),
product_name VARCHAR(255) NOT NULL,
description TEXT,
price DECIMAL(18,2) NOT NULL,
stock INT NOT NULL DEFAULT 0,
category_id INT NOT NULL,
created_at DATETIME NOT NULL DEFAULT GETDATE(),
updated_at DATETIME NOT NULL DEFAULT GETDATE()
);
GO

— 步骤3:创建分类表
CREATE TABLE fgedu.categories (
category_id INT PRIMARY KEY IDENTITY(1,1),
category_name VARCHAR(100) NOT NULL,
parent_id INT,
created_at DATETIME NOT NULL DEFAULT GETDATE(),
updated_at DATETIME NOT NULL DEFAULT GETDATE()
);
GO

— 步骤4:创建订单表
CREATE TABLE fgedu.orders (
order_id BIGINT PRIMARY KEY IDENTITY(1,1),
user_id INT NOT NULL,
order_date DATETIME NOT NULL DEFAULT GETDATE(),
total_amount DECIMAL(18,2) NOT NULL,
status VARCHAR(20) NOT NULL DEFAULT ‘PENDING’,
payment_method VARCHAR(50),
shipping_address VARCHAR(255),
tracking_number VARCHAR(100),
created_at DATETIME NOT NULL DEFAULT GETDATE(),
updated_at DATETIME NOT NULL DEFAULT GETDATE(),
CONSTRAINT FK_orders_users FOREIGN KEY (user_id) REFERENCES fgedu.users(user_id)
);
GO

— 步骤5:创建订单详情表
CREATE TABLE fgedu.order_items (
order_item_id BIGINT PRIMARY KEY IDENTITY(1,1),
order_id BIGINT NOT NULL,
product_id INT NOT NULL,
quantity INT NOT NULL,
unit_price DECIMAL(18,2) NOT NULL,
subtotal DECIMAL(18,2) NOT NULL,
created_at DATETIME NOT NULL DEFAULT GETDATE(),
CONSTRAINT FK_order_items_orders FOREIGN KEY (order_id) REFERENCES fgedu.orders(order_id),
CONSTRAINT FK_order_items_products FOREIGN KEY (product_id) REFERENCES fgedu.products(product_id)
);
GO

— 步骤6:创建购物车表
CREATE TABLE fgedu.cart_items (
cart_item_id INT PRIMARY KEY IDENTITY(1,1),
user_id INT NOT NULL,
product_id INT NOT NULL,
quantity INT NOT NULL,
created_at DATETIME NOT NULL DEFAULT GETDATE(),
updated_at DATETIME NOT NULL DEFAULT GETDATE(),
CONSTRAINT FK_cart_items_users FOREIGN KEY (user_id) REFERENCES fgedu.users(user_id),
CONSTRAINT FK_cart_items_products FOREIGN KEY (product_id) REFERENCES fgedu.products(product_id)
);
GO

— 步骤7:创建评价表
CREATE TABLE fgedu.reviews (
review_id INT PRIMARY KEY IDENTITY(1,1),
user_id INT NOT NULL,
product_id INT NOT NULL,
order_id BIGINT NOT NULL,
rating INT NOT NULL CHECK (rating BETWEEN 1 AND 5),
comment TEXT,
created_at DATETIME NOT NULL DEFAULT GETDATE(),
CONSTRAINT FK_reviews_users FOREIGN KEY (user_id) REFERENCES fgedu.users(user_id),
CONSTRAINT FK_reviews_products FOREIGN KEY (product_id) REFERENCES fgedu.products(product_id),
CONSTRAINT FK_reviews_orders FOREIGN KEY (order_id) REFERENCES fgedu.orders(order_id)
);
GO

— 步骤8:创建索引
CREATE NONCLUSTERED INDEX IX_products_category_id ON fgedu.products(category_id);
CREATE NONCLUSTERED INDEX IX_orders_user_id ON fgedu.orders(user_id);
CREATE NONCLUSTERED INDEX IX_orders_status ON fgedu.orders(status);
CREATE NONCLUSTERED INDEX IX_order_items_order_id ON fgedu.order_items(order_id);
CREATE NONCLUSTERED INDEX IX_cart_items_user_id ON fgedu.cart_items(user_id);
CREATE NONCLUSTERED INDEX IX_reviews_product_id ON fgedu.reviews(product_id);
GO

— 步骤9:创建分区表(针对订单表)
— 创建分区函数
CREATE PARTITION FUNCTION OrderDatePartitionFunc(DATETIME) AS RANGE RIGHT FOR VALUES (
‘2025-01-01’, ‘2025-02-01’, ‘2025-03-01’, ‘2025-04-01’,
‘2025-05-01’, ‘2025-06-01’, ‘2025-07-01’, ‘2025-08-01’,
‘2025-09-01’, ‘2025-10-01’, ‘2025-11-01’, ‘2025-12-01’
);
GO

— 创建分区方案
CREATE PARTITION SCHEME OrderDatePartitionScheme AS PARTITION OrderDatePartitionFunc ALL TO ([PRIMARY]);
GO

— 重新创建订单表为分区表
CREATE TABLE fgedu.orders_partitioned (
order_id BIGINT PRIMARY KEY IDENTITY(1,1),
user_id INT NOT NULL,
order_date DATETIME NOT NULL DEFAULT GETDATE(),
total_amount DECIMAL(18,2) NOT NULL,
status VARCHAR(20) NOT NULL DEFAULT ‘PENDING’,
payment_method VARCHAR(50),
shipping_address VARCHAR(255),
tracking_number VARCHAR(100),
created_at DATETIME NOT NULL DEFAULT GETDATE(),
updated_at DATETIME NOT NULL DEFAULT GETDATE()
) ON OrderDatePartitionScheme(order_date);
GO

— 添加外键
ALTER TABLE fgedu.orders_partitioned ADD CONSTRAINT FK_orders_partitioned_users FOREIGN KEY (user_id) REFERENCES fgedu.users(user_id);
GO

执行结果:

Commands completed successfully.

Commands completed successfully.

Commands completed successfully.

Commands completed successfully.

Commands completed successfully.

Commands completed successfully.

Commands completed successfully.

Commands completed successfully.

Commands completed successfully.

Commands completed successfully.

Commands completed successfully.

Commands completed successfully.

4.2 电商系统订单处理案例

订单处理实战:

— 案例:电商系统订单处理
— 步骤1:创建订单处理存储过程
CREATE PROCEDURE fgedu.sp_process_order
@user_id INT,
@order_items XML,
@total_amount DECIMAL(18,2),
@payment_method VARCHAR(50),
@shipping_address VARCHAR(255),
@out_order_id BIGINT OUTPUT
AS
BEGIN
SET NOCOUNT ON;
BEGIN TRY
BEGIN TRANSACTION;

— 创建订单
INSERT INTO fgedu.orders (
user_id,
total_amount,
status,
payment_method,
shipping_address
) VALUES (
@user_id,
@total_amount,
‘PENDING’,
@payment_method,
@shipping_address
);

SET @out_order_id = SCOPE_IDENTITY();

— 处理订单详情
DECLARE @item_xml XML;
DECLARE @product_id INT;
DECLARE @quantity INT;
DECLARE @unit_price DECIMAL(18,2);
DECLARE @subtotal DECIMAL(18,2);

DECLARE item_cursor CURSOR FOR
SELECT
T.c.value(‘@product_id’, ‘INT’),
T.c.value(‘@quantity’, ‘INT’),
T.c.value(‘@unit_price’, ‘DECIMAL(18,2)’),
T.c.value(‘@subtotal’, ‘DECIMAL(18,2)’)
FROM @order_items.nodes(‘/items/item’) T(c);

OPEN item_cursor;
FETCH NEXT FROM item_cursor INTO @product_id, @quantity, @unit_price, @subtotal;

WHILE @@FETCH_STATUS = 0
BEGIN
— 检查库存
DECLARE @stock INT;
SELECT @stock = stock
FROM fgedu.products
WHERE product_id = @product_id;

IF @stock < @quantity BEGIN RAISERROR('商品库存不足', 16, 1); END; -- 减少库存 UPDATE fgedu.products SET stock = stock - @quantity, updated_at = GETDATE() WHERE product_id = @product_id; -- 插入订单详情 INSERT INTO fgedu.order_items ( order_id, product_id, quantity, unit_price, subtotal ) VALUES ( @out_order_id, @product_id, @quantity, @unit_price, @subtotal ); -- 从购物车中删除 DELETE FROM fgedu.cart_items WHERE user_id = @user_id AND product_id = @product_id; FETCH NEXT FROM item_cursor INTO @product_id, @quantity, @unit_price, @subtotal; END; CLOSE item_cursor; DEALLOCATE item_cursor; COMMIT TRANSACTION; END TRY BEGIN CATCH ROLLBACK TRANSACTION; THROW; END CATCH; END; GO -- 步骤2:创建订单状态更新存储过程 CREATE PROCEDURE fgedu.sp_update_order_status @order_id BIGINT, @status VARCHAR(20), @tracking_number VARCHAR(100) = NULL AS BEGIN SET NOCOUNT ON; BEGIN TRY BEGIN TRANSACTION; -- 更新订单状态 UPDATE fgedu.orders SET status = @status, tracking_number = @tracking_number, updated_at = GETDATE() WHERE order_id = @order_id; -- 如果订单取消,恢复库存 IF @status = 'CANCELLED' BEGIN DECLARE @product_id INT; DECLARE @quantity INT; DECLARE order_item_cursor CURSOR FOR SELECT product_id, quantity FROM fgedu.order_items WHERE order_id = @order_id; OPEN order_item_cursor; FETCH NEXT FROM order_item_cursor INTO @product_id, @quantity; WHILE @@FETCH_STATUS = 0 BEGIN -- 恢复库存 UPDATE fgedu.products SET stock = stock + @quantity, updated_at = GETDATE() WHERE product_id = @product_id; FETCH NEXT FROM order_item_cursor INTO @product_id, @quantity; END; CLOSE order_item_cursor; DEALLOCATE order_item_cursor; END; COMMIT TRANSACTION; END TRY BEGIN CATCH ROLLBACK TRANSACTION; THROW; END CATCH; END; GO -- 步骤3:测试订单处理 -- 测试创建订单 DECLARE @order_id BIGINT; DECLARE @order_items XML = '‘;

EXEC fgedu.sp_process_order
@user_id = 1,
@order_items = @order_items,
@total_amount = 21997.00,
@payment_method = ‘Alipay’,
@shipping_address = ‘北京市朝阳区某某街道123号’,
@out_order_id = @order_id OUTPUT;
PRINT ‘订单ID: ‘ + CAST(@order_id AS VARCHAR(20));
GO

— 测试更新订单状态
EXEC fgedu.sp_update_order_status
@order_id = 1,
@status = ‘PAID’;
GO

EXEC fgedu.sp_update_order_status
@order_id = 1,
@status = ‘SHIPPED’,
@tracking_number = ‘SF1234567890’;
GO

— 步骤4:查询订单和库存
— 查询订单
SELECT order_id, user_id, order_date, total_amount, status, payment_method, shipping_address, tracking_number
FROM fgedu.orders
WHERE order_id = 1;
GO

— 查询订单详情
SELECT oi.order_item_id, oi.order_id, p.product_name, oi.quantity, oi.unit_price, oi.subtotal
FROM fgedu.order_items oi
JOIN fgedu.products p ON oi.product_id = p.product_id
WHERE oi.order_id = 1;
GO

— 查询商品库存
SELECT product_id, product_name, stock
FROM fgedu.products
WHERE product_id IN (1, 4);
GO

执行结果:

Commands completed successfully.

Commands completed successfully.

订单ID: 1

Commands completed successfully.

Commands completed successfully.

order_id user_id order_date total_amount status payment_method shipping_address tracking_number
———– ———– ———————– ———— ——– ————— ———————– —————
1 1 2025-04-08 10:00:00.000 21997.00 SHIPPED Alipay 北京市朝阳区某某街道123号 SF1234567890

(1 row affected)

order_item_id order_id product_name quantity unit_price subtotal
————- ———– ————- ———– ———– ———–
1 1 iPhone 15 Pro 2 9999.00 19998.00
2 1 AirPods Pro 1 1999.00 1999.00

(2 rows affected)

product_id product_name stock
———– ————- ———–
1 iPhone 15 Pro 98
4 AirPods Pro 199

(2 rows affected)

4.3 电商系统性能优化案例

性能优化实战:

— 案例:电商系统性能优化
— 步骤1:优化查询性能
— 创建索引
CREATE INDEX IX_products_price ON fgedu.products(price);
CREATE INDEX IX_orders_order_date ON fgedu.orders(order_date);
CREATE INDEX IX_order_items_product_id ON fgedu.order_items(product_id);
GO

— 优化查询语句
— 原始查询
SELECT *
FROM fgedu.products
WHERE category_id = 1
AND price BETWEEN 5000 AND 10000;

— 优化后的查询
SELECT product_id, product_name, price, stock
FROM fgedu.products
WHERE category_id = 1
AND price BETWEEN 5000 AND 10000
ORDER BY price DESC;
GO

— 步骤2:使用分区表
— 为订单表创建分区
— 已在前面创建,这里验证分区效果
SELECT
partition_number,
rows
FROM sys.partitions
WHERE object_id = OBJECT_ID(‘fgedu.orders_partitioned’);
GO

— 步骤3:使用内存优化表
— 创建内存优化表
CREATE TABLE fgedu.products_inmemory (
product_id INT IDENTITY(1,1) PRIMARY KEY NONCLUSTERED,
product_name VARCHAR(255) NOT NULL,
price DECIMAL(18,2) NOT NULL,
stock INT NOT NULL DEFAULT 0,
category_id INT NOT NULL
) WITH (MEMORY_OPTIMIZED = ON, DURABILITY = SCHEMA_AND_DATA);
GO

— 创建内存优化索引
CREATE NONCLUSTERED INDEX IX_products_inmemory_category_id ON fgedu.products_inmemory(category_id);
CREATE NONCLUSTERED INDEX IX_products_inmemory_price ON fgedu.products_inmemory(price);
GO

— 步骤4:使用存储过程优化
— 创建优化的存储过程
CREATE PROCEDURE fgedu.sp_get_products_by_category
@category_id INT,
@page_size INT = 20,
@page_number INT = 1
AS
BEGIN
SET NOCOUNT ON;
SET ARITHABORT ON;

DECLARE @offset INT = (@page_number – 1) * @page_size;

SELECT
product_id,
product_name,
price,
stock
FROM fgedu.products
WHERE category_id = @category_id
ORDER BY price DESC
OFFSET @offset ROWS FETCH NEXT @page_size ROWS ONLY;
END;
GO

— 步骤5:配置SQLServer性能选项
— 配置最大服务器内存
EXEC sp_configure ‘max server memory’, 32768;
RECONFIGURE;
GO

— 配置并行度
EXEC sp_configure ‘max degree of parallelism’, 8;
RECONFIGURE;
GO

— 配置查询优化器
EXEC sp_configure ‘cost threshold for parallelism’, 50;
RECONFIGURE;
GO

— 步骤6:监控性能
— 创建性能监控作业
USE msdb;
GO

EXEC dbo.sp_add_job
@job_name = N’EcommercePerformanceMonitor’,
@enabled = 1,
@description = N’Monitor SQL Server performance for e-commerce system’;
GO

EXEC dbo.sp_add_jobstep
@job_name = N’EcommercePerformanceMonitor’,
@step_name = N’Collect Performance Data’,
@subsystem = N’TSQL’,
@command = N’
INSERT INTO dbo.performance_monitor (
collection_time,
cpu_usage,
memory_usage,
io_usage,
active_connections,
slow_queries
)
SELECT
GETDATE(),
(SELECT TOP 1 cpu_percent FROM sys.dm_os_ring_buffers WHERE ring_buffer_type = ”RING_BUFFER_CPU_EXTENSION”),
(SELECT physical_memory_in_use_kb FROM sys.dm_os_process_memory),
(SELECT SUM(num_of_reads + num_of_writes) FROM sys.dm_io_virtual_file_stats(NULL, NULL)),
(SELECT COUNT(*) FROM sys.dm_exec_sessions WHERE is_user_process = 1),
(SELECT COUNT(*) FROM sys.dm_exec_requests WHERE cpu_time > 1000);
‘,
@database_name = N’msdb’;
GO

EXEC dbo.sp_add_jobschedule
@job_name = N’EcommercePerformanceMonitor’,
@name = N’Every 5 Minutes’,
@freq_type = 4,
@freq_interval = 1,
@freq_subday_type = 4,
@freq_subday_interval = 5,
@active_start_time = 000000,
@active_end_time = 235959;
GO

执行结果:

Commands completed successfully.

Commands completed successfully.

Commands completed successfully.

partition_number rows
—————- ——
1 0
2 0
3 0
4 1
5 0
6 0
7 0
8 0
9 0
10 0
11 0
12 0
13 0

(13 rows affected)

Commands completed successfully.

Commands completed successfully.

Commands completed successfully.

Configuration option ‘max server memory (MB)’ changed from 2147483647 to 32768. Run the RECONFIGURE statement to install.

Commands completed successfully.

Configuration option ‘max degree of parallelism’ changed from 0 to 8. Run the RECONFIGURE statement to install.

Commands completed successfully.

Configuration option ‘cost threshold for parallelism’ changed from 5 to 50. Run the RECONFIGURE statement to install.

Commands completed successfully.

(1 row affected)

(1 row affected)

(1 row affected)

Part05-风哥经验总结与分享

5.1 电商系统最佳实践

电商系统最佳实践:

  • 高可用设计:使用Always On Availability Groups确保数据库高可用
  • 读写分离:主库处理写操作,从库处理读操作,提高系统性能
  • 缓存策略:使用Redis等缓存,减少数据库访问,提高响应速度
  • 分区表:对大表进行分区,提高查询性能
  • 索引优化:为常用查询字段创建合适的索引
  • 事务管理:使用事务确保订单和库存数据的一致性
  • 监控与告警:建立完善的性能监控和告警机制
  • 备份与恢复:制定合理的备份策略,确保数据安全

更多视频教程www.fgedu.net.cn

5.2 电商系统常见问题

常见问题:

  • 性能瓶颈:促销活动期间并发量高,系统响应慢
  • 库存超卖:并发下单时出现库存超卖问题
  • 死锁:并发操作时出现死锁,影响系统稳定性
  • 数据一致性:网络故障或系统崩溃时的数据一致性问题
  • 扩展性:业务增长时系统扩展性不足
  • 安全风险:用户数据和交易数据的安全风险

学习交流加群风哥微信: itpux-com

5.3 电商系统性能优化

性能优化:

  • 数据库优化:使用索引、分区表、内存优化表等技术提高性能
  • 应用优化:优化代码逻辑,减少数据库访问
  • 缓存优化:合理使用缓存,缓存热点数据
  • 硬件优化:使用高性能存储和网络设备
  • 架构优化:采用微服务架构,提高系统扩展性
  • 负载均衡:使用负载均衡,分散系统压力
  • 监控与调优:定期监控性能,及时调优

学习交流加群风哥QQ113257174

风哥提示:电商系统对数据库的要求极高,需要综合考虑高并发、高性能和高可用性等因素,建立完善的数据库架构和管理体系,确保系统稳定运行。

更多学习教程公众号风哥教程itpux_com

from SQLServer视频:www.itpux.com

本文由风哥教程整理发布,仅用于学习测试使用,转载注明出处:http://www.fgedu.net.cn/10327.html

联系我们

在线咨询:点击这里给我发消息

微信号:itpux-com

工作日:9:30-18:30,节假日休息