查询设计
- 使用临时表:由于订单表数据量巨大,直接关联查询性能较差。可以先通过子查询统计每个商品的销售数量,将结果存储在临时表中,再与商品表进行关联查询。
-- 创建临时表统计每个商品的销售数量
CREATE TEMPORARY TABLE temp_sales AS
SELECT product_id, SUM(purchase_quantity) AS total_sales
FROM orders
GROUP BY product_id;
-- 从临时表和商品表中查询热门商品销售数据并排序
SELECT p.product_id, p.product_name, ts.total_sales
FROM products p
JOIN temp_sales ts ON p.product_id = ts.product_id
ORDER BY ts.total_sales DESC;
- 索引优化:
- 在
orders
表的product_id
和purchase_quantity
字段上创建复合索引,以加速子查询中的分组和求和操作。
CREATE INDEX idx_product_purchase ON orders (product_id, purchase_quantity);
- 在
products
表的product_id
字段上创建索引,以加速连接操作。
CREATE INDEX idx_product_id ON products (product_id);
性能剖析与优化
- 使用SHOW STATUS:
- 查询缓存命中率:通过
SHOW STATUS LIKE 'Qcache%';
查看查询缓存的相关状态,如Qcache_hits
(缓存命中次数)和Qcache_inserts
(缓存插入次数)。如果缓存命中率较低,可能需要调整查询缓存的配置或考虑其他缓存策略。
- InnoDB相关状态:使用
SHOW STATUS LIKE 'InnoDB%';
查看InnoDB引擎的状态,如InnoDB_buffer_pool_reads
(InnoDB缓冲池读次数)和InnoDB_buffer_pool_read_requests
(InnoDB缓冲池读请求次数)。如果读次数过高,可能需要增加缓冲池大小。
- 使用SHOW PROFILE:
- 开启查询剖析功能:
SET profiling = 1;
- 执行查询:
SELECT p.product_id, p.product_name, ts.total_sales FROM products p JOIN temp_sales ts ON p.product_id = ts.product_id ORDER BY ts.total_sales DESC;
- 查看剖析结果:
SHOW PROFILES;
找到对应查询的query_id
,然后SHOW PROFILE FOR QUERY [query_id];
查看详细的性能信息,如每个操作的执行时间、等待事件等,根据这些信息针对性地优化查询。
数据一致性问题
- 事务隔离级别:选择合适的事务隔离级别,如
READ - COMMITTED
,在保证数据一致性的前提下尽量减少锁的持有时间。可以通过SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
设置。
- 乐观锁与悲观锁:
- 悲观锁:如果对数据一致性要求极高,在查询热门商品销售数据时可以使用悲观锁,如
SELECT p.product_id, p.product_name, ts.total_sales FROM products p JOIN temp_sales ts ON p.product_id = ts.product_id ORDER BY ts.total_sales DESC FOR UPDATE;
,但这种方式会增加锁的竞争,影响并发性能。
- 乐观锁:在更新销售数据时,可以使用乐观锁机制。例如,在订单表中增加一个版本号字段
version
,每次更新销售数据时,先读取当前版本号,更新时带上版本号并检查版本号是否匹配,如果匹配则更新成功并递增版本号,否则重试。
-- 假设orders表有version字段
START TRANSACTION;
-- 读取订单数据及版本号
SELECT purchase_quantity, version FROM orders WHERE order_id = [order_id] FOR UPDATE;
-- 更新销售数据,假设新的购买数量为new_purchase_quantity
UPDATE orders SET purchase_quantity = purchase_quantity + new_purchase_quantity, version = version + 1 WHERE order_id = [order_id] AND version = [old_version];
COMMIT;