求一个数据表设计的思路!

2022-08-09 19:52:59 +08:00
 sunmoon1983

数据库为 MySQL5.7 一张表table1吧里面有 30W+数据,字段为id bigint(20),full_name varchar(66) province bigint(20),city JSON, county JSON 要展示符合下面这些条件的记录: 注意:city 和 county 储存的数据为地区的编码,如 city=["123456","234567","345678"],county=["5123456","6234567","7345678"]这种,我可以修改数据表结构

现在有一个搜索的需求,想要按照 city 和 county 搜索对应的数据,比如,搜索的条件为前端发送过来的,province=12345,city=["234567","345678"],county=["7345678","6234567"] 就是说,搜索的 city 和 county 可以是多选的! 我要怎么设计数据表才能够方便搜索呢?求大神解惑

4464 次点击
所在节点    MySQL
38 条回复
rrfeng
2022-08-09 19:55:49 +08:00
拆成两张表,或者直接拍扁。
sunmoon1983
2022-08-09 20:05:49 +08:00
@rrfeng 没太懂,是要搞一张 city county 和数据的关系表吗?
Maboroshii
2022-08-09 20:23:51 +08:00
for 循环分别搜吧
wxf666
2022-08-09 20:30:10 +08:00
@sunmoon1983 你要求速度吗?还是直接全表扫描?

可以接受全表扫描的话,直接 JSON_CONTAINS 呗


WITH
  DATA(province, city, county) AS (
   VALUES
    ROW(12345, '["123456","234567","345678"]', '["5123456","6234567","7345678"]'),
    ROW(12345, '["123456","2345678","345678"]', '["5123456","6234567","7345678"]')
 )

SELECT *
FROM DATA
WHERE province = 12345
  AND JSON_CONTAINS(city, CAST('["234567","345678"]' AS JSON))
  AND JSON_CONTAINS(county, CAST('["7345678","6234567"]' AS JSON))
leonme
2022-08-09 20:32:46 +08:00
方法 1 、先根据 province 过滤数据,然后在内存中过滤 city 和 country 。 方法 2 、city 和 country 重新设计,拍平存,不要聚合后再存,不然查询效率低。 方法 3 、采用 ES 查询
sunmoon1983
2022-08-09 20:32:59 +08:00
@wxf666 运营会经常搜索,肯定会有速度要求的,大佬
sunmoon1983
2022-08-09 20:34:12 +08:00
@leonme 拍平存是啥意思?没太懂
leonme
2022-08-09 20:36:54 +08:00
@sunmoon1983 单独的 city 字段,然后记录 province 和 city 的关联关系
wxf666
2022-08-09 20:55:25 +08:00
@sunmoon1983 我很好奇,不是 省 一对多 市 一对多 县 吗? 为啥存了 县,还要存 市 和 省 呢?
kran
2022-08-09 21:27:23 +08:00
json_search/json_contains
copper20
2022-08-09 23:24:39 +08:00
如果单独考虑这个需求的话,或许可以把 city 和 county 挪到另外的表里存。设计 foo_city(id, city) 表和 foo_county(id, county) 表,id 和 city / id 和 county 都设为主键(就是说直接设计两个关系表),然后在这两个表上分别建 city 字段和 county 字段上的索引,另外在现在的 table1 的 province 上也建立索引

捞数据的时候可以直接:

(SELECT
table1.idtable1
FROM
table1
INNER JOIN
(SELECT
idtable1
FROM
foo_county
WHERE
county = <county code>) co
INNER JOIN
(SELECT
idtable1
FROM
foo_city
WHERE
city = <city code>) ci
WHERE
province = <procince code>)

不过话说回来,地区代码这种事情用 varchar 存国标的地区代码,检索的时候直接用 LIKE "110101%" 之类的,用得上索引,而且代码上会方便许多吧
wxf666
2022-08-09 23:42:37 +08:00
@copper20 这个 SQL ,如何检索多个值呢?

city=["234567","345678"]

county=["7345678","6234567"]
LeeReamond
2022-08-10 03:02:46 +08:00
有多字段需求要拆表,你现在这种每行里存列表的形式没法多段索引的。比如需求上 city 需要 in 搜索,那 city 就必须是单独一列,每行只储存一个 city 和它对应的对象 id ,这样才可以 in a,b,c city 这么搜索,其他列同理
hoopan
2022-08-10 08:36:32 +08:00
这个表好奇怪,是存省市区的表? city 跟 county 怎么对应?
xaplux
2022-08-10 08:43:52 +08:00
如果是精确匹配,将 JSON 拆分成关系表
如果是模糊匹配,那上 ES 吧
copper20
2022-08-10 09:17:24 +08:00
@wxf666 把等于运算符换成 IN 运算符吧 比如就 county IN (1, 3)
panda1079
2022-08-10 09:39:34 +08:00
对于这种可扩展又参差不齐的数据我推荐你用 mongo
wxf666
2022-08-10 09:50:10 +08:00
@copper20 『 county IN (1, 3)』没有表现出『 1 、3 必须同时存在』的意思吧,而是『 1 、3 有其一出现即可』?
Saxton
2022-08-10 10:03:27 +08:00
难为 mysql 了
pannanxu
2022-08-10 10:23:00 +08:00
```sql
create table table1
(
id bigint primary key,
full_name varchar(66)
);

create table tab1_mapping
(
id bigint primary key,
table1_id bigint,
province bigint,
city int,
county int,
index (table1_id),
index (province, city, county)

);

select *
from table1 t1
inner join tab1_mapping t1m on t1.id = t1m.table1_id
where province = 1
and city in (1, 2, 3)
and county in (1, 2, 3)
```

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/871762

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX