Agent技能层实战拆解:让大模型真正会用工具的落地指南
2026/10/13 15:49:42
实现上一页和下一页,不是简单地用LIMIT offset, size,而是通过游标分页(Cursor-based Pagination)实现高性能、可扩展的分页。
-- 跳过 100 万行 → 扫描 1,000,010 行SELECT*FROMordersLIMIT1000000,10;-- 仅扫描 10 行SELECT*FROMordersWHEREid>1000000ORDERBYidLIMIT10;💡核心认知:
“上一页/下一页” = 记录当前页首尾 ID,而非计算偏移量
-- 创建测试表CREATETABLEproducts(idINTAUTO_INCREMENTPRIMARYKEY,nameVARCHAR(255)NOTNULL,priceDECIMAL(10,2)NOTNULL);-- 插入测试数据INSERTINTOproducts(name,price)VALUES('Product 1',10.00),('Product 2',20.00),...('Product 100',1000.00);<?php// config.php$pdo=newPDO('mysql:host=localhost;dbname=test','user','pass');$pdo->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);// pagination.phpfunctiongetProducts($pdo,$direction='next',$cursor=null,$limit=10){if($direction==='next'){// 下一页:id > cursor$sql="SELECT * FROM products WHERE id > :cursor ORDER BY id ASC LIMIT :limit";$params=['cursor'=>$cursor??0,'limit'=>$limit];}else{// 上一页:id < cursor,按降序取,再反转$sql="SELECT * FROM products WHERE id < :cursor ORDER BY id DESC LIMIT :limit";$params=['cursor'=>$cursor,'limit'=>$limit];}$stmt=$pdo->prepare($sql);$stmt->bindValue(':cursor',$params['cursor'],PDO::PARAM_INT);$stmt->bindValue(':limit',$params['limit'],PDO::PARAM_INT);$stmt->execute();$rows=$stmt->fetchAll(PDO::FETCH_ASSOC);// 上一页结果需反转if($direction==='prev'){$rows=array_reverse($rows);}return$rows;}// 获取当前页数据$direction=$_GET['direction']??'next';$cursor=$_GET['cursor']??null;$products=getProducts($pdo,$direction,$cursor);// 提取首尾 ID$firstId=$products?$products[0]['id']:null;$lastId=$products?end($products)['id']:null;?><!-- index.php --><!DOCTYPEhtml><html><head><title>产品列表</title></head><body><h1>产品列表</h1><ul><?php foreach ($products as $product): ?><li><?= htmlspecialchars($product['name']) ?>- $<?= $product['price'] ?></li><?php endforeach; ?></ul><!-- 分页按钮 --><div><?php if ($firstId): ?><ahref="?direction=prev&cursor=<?= $firstId ?>">上一页</a><?php endif; ?><?php if ($lastId): ?><ahref="?direction=next&cursor=<?= $lastId ?>">下一页</a><?php endif; ?></div></body></html>cursor = 当前页最后一条的 idWHERE id > cursor ORDER BY id ASCcursor = 当前页第一条的 idWHERE id < cursor ORDER BY id DESC(倒序取)array_reverse()还原顺序cursor = null→WHERE id > 0| 陷阱 | 破局方案 |
|---|---|
| 忽略 XSS 风险 | 输出时用htmlspecialchars() |
| 未处理空结果 | 检查$products是否为空 |
| 并发插入导致漏数据 | 接受最终一致性(业务可容忍) |
| 非自增主键 | 确保排序字段是聚簇索引 |
**“分页不是跳转,
而是锚点的传递——
- 当你记录首尾 ID,
你在跳过扫描;- 当你反转上一页,
你在还原顺序;- 当你隐藏无效按钮,
你在优化体验。真正的分页,
始于对索引的敬畏,
成于对细节的精控。”
从今天起:
array_reverse()处理htmlspecialchars()因为最好的分页,
不是计算偏移,
而是精准传递每一程的锚点。