尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

实战:上亿数据如何秒查

实战:上亿数据如何秒查 实战上亿数据如何秒查各位老铁今天咱们来聊一个非常“硬核”的话题——当你的数据库里躺着上亿条数据用户点一下查询按钮你却让他等5秒钟这体验简直比杀了他还难受。别慌今天我就带你从“慢如蜗牛”到“秒开页面”手把手搞定上亿数据的高效查询。### 一、为什么你的查询会慢很多人一上来就甩锅给“数据量太大”其实不然。数据量大只是“诱因”真正的“病根”往往是这几个1.没走索引全表扫描好比你在一个没有目录的图书馆里找一本书只能一本一本翻。2.查询语句写得太“烂”比如在索引列上用了函数、隐式类型转换导致索引失效。3.返回了太多无用数据明明只要前10条你却把100万条全查出来再丢弃。4.硬件/架构瓶颈单机磁盘IO、内存不足或者没有做读写分离。### 二、核心武器索引优化索引就是数据库的“目录”。建好索引查询就是“按图索骥”没建索引就是“大海捞针”。#### 1. 最左前缀法则假设我们有一张用户表user包含id, name, age, city, created_at。我们经常按(city, age)查询。sql-- 错误示范这样查如果只有 city 索引age 条件无法利用索引SELECT * FROM user WHERE age 25 AND city 北京;-- 正确示范建立联合索引 (city, age)并且查询条件顺序与索引一致或最左前缀匹配CREATE INDEX idx_city_age ON user(city, age);SELECT * FROM user WHERE city 北京 AND age 25;注意联合索引要遵守“最左前缀”原则。如果你只查age而不带city那这个联合索引就废了。#### 2. 覆盖索引避免回表如果你要查询的字段都包含在索引里那数据库就不用回表查原数据行速度会快好几倍。sql-- 假设我们只需要 city 和 age并且建立了 (city, age) 联合索引-- 这个查询就会用到覆盖索引速度极快SELECT city, age FROM user WHERE city 上海;#### 3. 索引失效的坑-对索引列使用函数WHERE YEAR(created_at) 2023会让索引失效应该改成WHERE created_at 2023-01-01 AND created_at 2024-01-01。-隐式类型转换如果id是 varchar 类型你写成WHERE id 123那数据库会把id转成数字索引失效。-LIKE 以 % 开头WHERE name LIKE %张%无法用索引但WHERE name LIKE 张%可以。### 三、分页查询的“陷阱”与优化上亿数据分页是家常便饭。但你有没有发现翻到后面几页速度越来越慢比如sql-- 这种查询越到后面越慢因为数据库要扫描并丢弃前面所有行SELECT * FROM user ORDER BY id LIMIT 1000000, 20;优化方案使用“延迟关联”或“书签”法。python# 伪代码示例记录上一页最后一条数据的 id然后下一页只查 id 上一页最后一个id 的数据# 比如上一页最后一个 id 是 1000020那么下一页就这么查# SELECT * FROM user WHERE id 1000020 ORDER BY id LIMIT 20# 这样永远只扫描 20 条速度恒定。### 四、实战亿级数据秒查方案代码示例我们来写一个完整的 Python MySQL 的优化查询示例。假设我们有一个订单表orders有 1 亿条数据。#### 场景按用户ID查最近10条订单pythonimport mysql.connectordef get_recent_orders_by_user(user_id, limit10): 优化点 1. 在 (user_id, created_at) 上建联合索引 2. 只查需要的字段避免 SELECT * 3. 使用 LIMIT 限制返回行数 conn mysql.connector.connect( hostlocalhost, userroot, passwordyour_password, databasebig_data_db ) cursor conn.cursor(dictionaryTrue) # 核心 SQL强制走索引并且只取需要的列 query SELECT order_id, amount, created_at FROM orders WHERE user_id %s ORDER BY created_at DESC LIMIT %s # 这里如果 (user_id, created_at) 有联合索引这个查询就是“索引有序扫描”非常快 cursor.execute(query, (user_id, limit)) results cursor.fetchall() cursor.close() conn.close() return results# 调用示例假设 user_id 12345# orders get_recent_orders_by_user(12345)# print(orders)#### 场景统计某天订单总额pythondef get_daily_total_order_amount(target_date): 优化点 1. 在 created_at 上建索引或与 user_id 建联合索引 2. 使用日期范围查询避免对列使用函数 3. 只返回聚合结果不返回明细 conn mysql.connector.connect( hostlocalhost, userroot, passwordyour_password, databasebig_data_db ) cursor conn.cursor(dictionaryTrue) # 正确写法用 和 来限定日期范围而不是 YEAR(created_at) 2023 query SELECT SUM(amount) as total_amount, COUNT(*) as order_count FROM orders WHERE created_at %s AND created_at %s start f{target_date} 00:00:00 end f{target_date} 23:59:59 cursor.execute(query, (start, end)) result cursor.fetchone() cursor.close() conn.close() return result# 调用示例# daily_stats get_daily_total_order_amount(2025-01-01)# print(daily_stats)### 五、进阶分库分表与缓存如果单表数据量太大索引优化已经到极限就需要考虑“分库分表”了。比如按用户ID哈希取模把数据分散到 64 张表里。这样单表数据量就降到百万级别查询自然快。另外对于热点数据比如首页推荐、排行榜可以用 Redis 缓存。查询时先查缓存缓存没有再去查数据库并回填缓存。pythonimport redisr redis.Redis(hostlocalhost, port6379, db0)def get_user_hot_data(user_id): # 先查缓存 cache_key fuser_hot:{user_id} cached_data r.get(cache_key) if cached_data: return cached_data # 缓存没有查数据库这里省略具体 SQL data query_from_db(user_id) # 写入缓存设置过期时间 60 秒 r.setex(cache_key, 60, data) return data### 六、总结上亿数据“秒查”并不是玄学核心思路是1.索引是根本合理设计索引避免索引失效。2.查询要“瘦身”只查需要的字段用 LIMIT 限制避免大范围扫描。3.分页有技巧用“书签”方式代替大偏移量。4.架构要升级分库分表、读写分离、缓存该上就上。记住没有银弹只有适合你业务场景的组合拳。你先从索引和 SQL 优化做起一般都能从“秒级”变成“毫秒级”。如果还不行再考虑分库分表和缓存。希望今天的实战经验能帮到你有问题欢迎在评论区交流
返回列表