本文目录导读:

在PHP项目中实现同城筛选,推荐使用数据库分组查询(GROUP BY) + 城市索引优化的方式,以下是几种常见实现方案:
MySQL原生分组查询(推荐)
数据库表结构
CREATE TABLE `users` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(50) DEFAULT NULL, `city` varchar(20) DEFAULT NULL, -- 城市名称 `city_code` varchar(10) DEFAULT NULL, -- 城市编码,可选 `province` varchar(20) DEFAULT NULL, `longitude` decimal(10,7) DEFAULT NULL, `latitude` decimal(10,7) DEFAULT NULL, PRIMARY KEY (`id`), KEY `idx_city` (`city`) -- 城市索引 ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
按城市分组查询数据
// 获取所有城市及其数据数量
$sql = "SELECT city, COUNT(*) as count
FROM users
GROUP BY city
ORDER BY count DESC";
$result = $db->query($sql);
$cityGroups = [];
while ($row = $result->fetch_assoc()) {
$cityGroups[] = $row;
}
查询指定城市的详细数据
// 获取某城市的详细数据
$city = $_GET['city'] ?? ''; // 前端传递的城市参数
$sql = "SELECT * FROM users WHERE city = ?";
$stmt = $db->prepare($sql);
$stmt->bind_param('s', $city);
$stmt->execute();
$result = $stmt->get_result();
$users = $result->fetch_all(MYSQLI_ASSOC);
使用Redis进行缓存分组
缓存城市分组数据
// 缓存城市分组数据
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
// 获取城市分组数据(缓存24小时)
$cityGroups = $redis->get('city_groups');
if (!$cityGroups) {
// 从数据库获取
$sql = "SELECT city, COUNT(*) as count
FROM users
GROUP BY city";
$result = $db->query($sql);
$cityGroups = $result->fetch_all(MYSQLI_ASSOC);
// 缓存到Redis
$redis->setex('city_groups', 86400, json_encode($cityGroups));
} else {
$cityGroups = json_decode($cityGroups, true);
}
按城市存储用户ID
// 插入数据时同时维护城市分组
function insertUser($data) {
global $db, $redis;
// 插入数据库
$sql = "INSERT INTO users (name, city) VALUES (?, ?)";
$stmt = $db->prepare($sql);
$stmt->bind_param('ss', $data['name'], $data['city']);
$stmt->execute();
$userId = $db->insert_id;
// 更新Redis城市分组
$redis->sAdd("city:{$data['city']}", $userId);
$redis->expire("city:{$data['city']}", 86400);
return $userId;
}
// 查询某城市用户
function getUsersByCity($city) {
global $db, $redis;
// 从Redis获取用户ID列表
$userIds = $redis->sMembers("city:{$city}");
if (!empty($userIds)) {
$ids = implode(',', $userIds);
$sql = "SELECT * FROM users WHERE id IN ($ids)";
$result = $db->query($sql);
return $result->fetch_all(MYSQLI_ASSOC);
}
return [];
}
Elasticsearch搜索引擎(大数据量推荐)
安装Elasticsearch-PHP客户端
composer require elasticsearch/elasticsearch
索引数据
use Elasticsearch\ClientBuilder;
$client = ClientBuilder::create()->build();
// 批量索引数据
$params = ['body' => []];
foreach ($users as $user) {
$params['body'][] = [
'index' => [
'_index' => 'users',
'_id' => $user['id']
]
];
$params['body'][] = [
'name' => $user['name'],
'city' => $user['city'],
'province' => $user['province']
];
}
$responses = $client->bulk($params);
按城市聚合查询
// 城市分组聚合查询
$params = [
'index' => 'users',
'body' => [
'size' => 0,
'aggs' => [
'by_city' => [
'terms' => [
'field' => 'city.keyword',
'size' => 100 // 最多返回100个城市
]
]
]
]
];
$response = $client->search($params);
$buckets = $response['aggregations']['by_city']['buckets'];
foreach ($buckets as $bucket) {
echo "城市: " . $bucket['key'] . ",数量: " . $bucket['doc_count'] . "<br>";
}
// 查询指定城市数据
$params = [
'index' => 'users',
'body' => [
'query' => [
'term' => [
'city.keyword' => '北京'
]
]
]
];
$response = $client->search($params);
$users = $response['hits']['hits'];
前端展示示例
<!-- 城市筛选下拉框 -->
<select id="citySelect" onchange="filterByCity()">
<option value="">全部城市</option>
<?php foreach ($cityGroups as $city): ?>
<option value="<?php echo $city['city']; ?>">
<?php echo $city['city'] . ' (' . $city['count'] . ')'; ?>
</option>
<?php endforeach; ?>
</select>
<!-- 数据列表 -->
<div id="userList">
<?php foreach ($users as $user): ?>
<div class="user-item">
<span><?php echo $user['name']; ?></span>
<span><?php echo $user['city']; ?></span>
</div>
<?php endforeach; ?>
</div>
<script>
function filterByCity() {
var city = document.getElementById('citySelect').value;
window.location.href = '?city=' + city;
}
</script>
性能优化建议
- 索引优化:确保
city字段有索引 - 分页查询:使用
LIMIT限制返回数据量 - 缓存策略:对城市分组结果设置缓存
- 数据分片:大数据量考虑MySQL分表或MongoDB
- 异步加载:使用AJAX实现无刷新筛选
选择建议
- 数据量 < 10万:MySQL分组查询即可
- 数据量 10万-100万:Redis缓存分组
- 数据量 > 100万:Elasticsearch搜索引擎
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播