数据库执行=搜索时速度很快,执行 IN 搜索时速度很慢是什么原因?

220 天前
 FlyingBackscratc

表里存的传感器回报信号数据,因为数据量不大,没用时序数据库因为感觉关系型跑的也挺好的。

表里只有三列,rid(自增主键),传感器编号 sid ,上报时间 datetime 。在 sid 和 datetime 上有联合索引。

之前做基准测试的时候只做了单点的,就是

SELECT ... FROM records WHERE sid=0 ORDER BY datetime ASC LIMIT 10

类似这种感觉的,运行速度是很快的,平均延迟低于 100 毫秒,解释分析也确实是走索引了

但是最近改成多栏目搜索后

SELECT ... FROM records WHERE sid IN (0, 1, 2) ORDER BY datetime ASC LIMIT 10

解释分析也是走索引的,但是执行时间会超过 1 分钟。

这是啥原因?数据量两亿行左右。

4048 次点击
所在节点    程序员
42 条回复
tslling
219 天前
我觉得 18 楼和 21 楼是正解。sid=0,1,2 的数据分别有多少条呀
billccn
219 天前
看第二张图,优化器给你生成了一个临时的缓存在磁盘上的 View ,并行读了 8 百万行原表,把所有符合条件的行都复制过去了,最后从 View 里面选出了前 10 个返回。而第一张图之是分两次查原表,各读满 10 个以后截断,然后 Union 。

原因 1 是你这两个查询的语义本来就不一样,你的第一张图可以输出 20 个结果,且每个 sid 里面的时间排序相互独立。第二张是一共输出 10 个结果,而且是从三个 SID 结果的合集中再按照时间排序。

原因 2 是 Oracle 的 fetch first 功能是后来加的 hack ,没有很好的融合进构架里面去,它不影响默认的全局优化策略(ALL_ROWS ,这导致优化器会先忽略你只要前面几行的要求,它会生成一个找到所有符合要求的结果最快的 plan ,然后在最外层加一个附加条件来输出前面几个结果。你需要在 select 后面加/*+ FIRST_ROWS(10) */这个 hint ( 10 是需要的行数),让它进入前几行行输出速度优先模式。

原因 3 是根据我的经验,Oracle 犯这个傻也跟这个数据库的配置有关,优化器可能觉得 IO 成本很低,所以用每一个 sid 单独查(就是你第一张图想表达的模式)的那个 plan 反而被当作成本过高而弃用了。

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

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

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

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

© 2021 V2EX