60.
@老虎会游泳,我测试了下,Python 生成 1KW 个数字(0~1KW-1),然后变成 json 字符串,给 sqlite 计算出 min、max、count,
我的渣笔记本用时 3 秒
import time
begin = time.time()
import json
import sqlite3
db = sqlite3.connect(':memory:')
print(db.execute(
'SELECT count(*), min(value), max(value) FROM json_each(?)',
(json.dumps(list(range(10000000))),),
).fetchone())
db.close()
print(time.time() - begin)
结果:
(10000000, 0, 9999999)
2.8264474868774414
61.
@老虎会游泳,看来表值函数实现不算差,有瓶颈也不会出现在这儿
62.
@无名啊,哦,看起来它有一些非关系型数据库的功能了。如果JSON_CONTAINS
可以利用索引,那么它确实是最佳解决方案。
不过,这个解决方案不仅依赖其他编程语言(需要其他编程语言进行JSON拼接),还依赖SQL拼接(需要对条件1 AND 条件2 AND 条件3...
进行拼接)
63.
@老虎会游泳,我觉得拼接参数优于拼接SQL。后者的解析可能很耗时,对于 执行计划 的计算可能也有影响(不是说是用到动态规划么。。O(N^2)那种?)
64.
@老虎会游泳,可如果你去看下『多值索引』的底层存储,发现还是关系数据库。。
这里有个解析:https://zhuanlan.zhihu.com/p/115802841
发现还是展开来存。。比如 (id: 1, has: ["aa", "bb"]) 就存成 ("aa" -> 1)("bb" -> 1)。。
估计这也解释了为何一个索引,不能有多个多值字段吧(否则就数量爆炸了:一行记录,对应 count(多值字段一) * count(多值字段二) * ... 行索引)
65.
@tasy5kg,如果是要找 哪些用户听过了(歌曲1,歌曲2,……歌曲n),且关注了(歌手1,歌手2,……,歌手n),咋写呀
66.
@无名啊,
拼接参数优于拼接SQL
确实。不过经典的关系型数据库没办法用一个参数传递多个值,拼接SQL是必然选择。MySQL的JSON_CONTAINS
已经超出关系型数据库的范畴了。
而且就算用JSON_CONTAINS
,想同时匹配多个字段,还是绕不过SQL拼接。JSON_CONTAINS(字段1, ...) AND JSON_CONTAINS(字段2, ...)
,这里的AND
、字段1
和字段2
似乎必须在SQL里,没有办法仅靠参数就进行传递。
67.
@老虎会游泳,一般字段数在设计表时就定了吧(也意味着,代码里一般也写死SQL了)
69.
@无名啊,但是用户的查询条件不确定啊。为什么我一定要搜索技能
+手机
呢?我不能只搜索技能
,或者只搜索手机
吗?你不拼接SQL,难道你要写三个函数来分别处理不同的查询条件组合吗?
70.
@老虎会游泳,
我不这么认为。
你瞅了刚才发的那篇文章地址了吗?别人分析了多值索引底层存储结构:
原表:
[root@yejr.me]> select id, custinfo->'$.zipcode' from customers;
+----+-----------------------+
| id | custinfo->'$.zipcode' |
+----+-----------------------+
| 1 | [94582, 94536] |
| 2 | [94568, 94507, 94582] |
| 3 | [94477, 94507] |
| 4 | [94536] |
| 5 | [94507, 94582] |
+----+-----------------------+
二级索引的底层存储:
+---------+------+
| zipcode | id |
+---------+------+
| 94477 | 3 |
| 94507 | 2 |
| 94507 | 3 |
| 94507 | 5 |
| 94536 | 1 |
| 94536 | 4 |
| 94568 | 2 |
| 94582 | 1 |
| 94582 | 2 |
| 94582 | 5 |
+---------+------+
71.
@老虎会游泳,然后你就发现,这不就是『员工技能表』『员工手机表』么。。
73.
@无名啊,这和索引有什么关系,那只是具体实现,而关系型数据库是一个抽象概念,不需要考虑具体实现。
关系型数据库是二维表,也就是说,表中每个单元格要么没有值(为NULL),要么只有唯一一个值,这个值能和数据库中其他单元格的值直接建立联系。
但是JSON字段显然打破了这个假设,这个单元格有多个值,和其他单元格中的值也没办法直接建立联系,必须先提取JSON的某个值才能和其他非JSON字段建立联系。
也就是说,带JSON字段的表不是二维的,取决于JSON的结构,它可能是三维、四维、五维……的。我不认为这依然属于关系型数据库。
74.
@老虎会游泳,
但是用户的查询条件不确定啊。为什么我一定要搜索技能
+手机
呢?我不能只搜索技能
,或者只搜索手机
吗?你不拼接SQL,难道你要写三个函数来分别处理不同的查询条件组合吗?
改写下 SQL 就好了啊
SELECT *
FROM 员工表
WHERE (?1 IS NULL OR JSON_CONTAINS(这个员工会的技能, CAST(?1 AS JSON)))
AND (?2 IS NULL OR JSON_CONTAINS(这个员工有的手机, CAST(?2 AS JSON)))
75.
@无名啊,当然,如果你说“JSON索引其实相当于一个独立的表”、“JSON字段只是INNER JOIN的语法糖”,那也确实成立,那可以把这个模型继续视为关系型数据库。
76.
@老虎会游泳,我觉得,现阶段的 json 字段还是当字符串看待的(至少 SQLite 是这样)?
77.
@无名啊,相比于IS NULL OR
,我更喜欢拼接AND
语句,因为这是把命运掌握在自己手中,而不是交给SQL优化器。
而且,你生成了单个复杂SQL,初次解析需要更久时间,并且每次跑优化器匹配IS NULL
也需要一段时间(因为参数是否为NULL不能提前确定)。
我虽然最终会生成三个不同的SQL,但是没有多余条件,不会在优化器里浪费时间。而且预处理+查询缓存,也只是首次解析三个SQL需要一点时间而已。因为SQL更简单,解析起来不见得比单个复杂SQL慢。
78.
@无名啊,当然,你可以说我在拼接SQL时浪费了时间。所以哪个更快依然不好说。这只能属于个人选择。
79.
@老虎会游泳,MySQL 的执行优化,真的那么蠢吗。。
是不是要衬托出甲骨文的商业产品 Oracle 的强大。。
这就是收购 MySQL 的考虑?(别发展太强?)