为什么有些时候用prewhere是错误的。
Prewhere和where语句的作用相同,用来过滤数据。不同之处在于prewhere只支持*MergeTree族系列引擎的表,首先会读取指定的列数据,来判断数据过滤,等待数据过滤之后再读取select声明的列字段来补全其余属性。
当查询列明显多于筛选列时使用PreWhere可十倍提升查询性能,Prewhere会自动优化执行过滤阶段的数据读取方式,降低io操作。参数optimize_move_to_prewhere=1为开启状态,可以设置为0对其关闭。
在某些场合下,prewhere语句比where语句处理的数据量更少性能更高。
默认情况,我们肯定不会关闭where自动优化成prewhere,但是某些场景即使开启优化,也不会自动转换成prewhere,需要手动指定prewhere:
- 使用常量表达式
- 使用默认值为alias类型的字段
- 包含了arrayJOIN,globalIn,globalNotIn或者IndexHint的查询
- select查询的列字段和where的谓词相同
- 使用了主键字段
由于prewhere会在聚合阶段前去拿数据,对于一些易变的字段就不适合用prewhere。
那如果我的表数据只做存储是不是意味着没有什么可变字段
不完全是这样。即使表数据主要用于存储,也并不意味着没有可变字段,也不意味着可以随意使用 PREWHERE
。以下是几个关键点:
- 数据变更:
- 即使表主要用于存储,某些字段的值仍然可能会随时间而改变。例如,您可能有一个字段用于记录数据的最后修改时间,或者一个状态字段表示数据的当前状态。
- PREWHERE 的使用场景:
PREWHERE
主要用于在数据读取阶段进行过滤,以减少I/O操作并提升性能。- 通常,
PREWHERE
中应放置那些用于分区或索引的字段,因为它们通常不会频繁更改,并且这些字段的过滤可以显著减少需要读取的数据量。- 选择 WHERE 还是 PREWHERE:
- 如果一个字段经常变更,那么它不适合放在
PREWHERE
中,因为该字段的变更可能会导致查询计划失效或性能下降。- 在设计查询时,应该分析查询的模式和数据的特点,以确定哪些字段适合放在
PREWHERE
中,哪些字段应该放在WHERE
中。- 存储和查询性能:
- 存储和查询性能是两个不同的关注点。即使表主要用于存储,也需要考虑如何高效地查询这些数据。
- 使用
PREWHERE
和其他优化技术(如索引、分区等)可以帮助提高查询性能。- 注意事项:
- 并非所有查询都需要或能够从
PREWHERE
中受益。在某些情况下,简单的WHERE
子句可能就足够了。PREWHERE
的使用也取决于具体的数据库管理系统(如ClickHouse)和它的优化器如何工作。