filter-pushdown.slt 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  1. # Copyright Materialize, Inc. and contributors. All rights reserved.
  2. #
  3. # Use of this software is governed by the Business Source License
  4. # included in the LICENSE file at the root of this repository.
  5. #
  6. # As of the Change Date specified in that file, in accordance with
  7. # the Business Source License, use of this software will be governed
  8. # by the Apache License, Version 2.0.
  9. mode cockroach
  10. simple conn=mz_system,user=mz_system
  11. ALTER SYSTEM SET persist_stats_filter_enabled = true
  12. ----
  13. COMPLETE 0
  14. # Verify filter pushdown information for various temporal filters.
  15. # For straightforward temporal filters like these, every column mentioned in the filter
  16. # should be present in the pushdown list.
  17. statement ok
  18. CREATE TABLE events (
  19. content text,
  20. insert_ms numeric,
  21. delete_ms numeric
  22. );
  23. query T multiline
  24. EXPLAIN OPTIMIZED PLAN WITH(humanized expressions, filter pushdown) AS VERBOSE TEXT FOR
  25. SELECT count(*)
  26. FROM events
  27. WHERE mz_now() >= insert_ms
  28. AND mz_now() < delete_ms;
  29. ----
  30. Explained Query:
  31. With
  32. cte l0 =
  33. Reduce aggregates=[count(*)]
  34. Project ()
  35. Filter (mz_now() < numeric_to_mz_timestamp(#2{delete_ms})) AND (mz_now() >= numeric_to_mz_timestamp(#1{insert_ms}))
  36. ReadStorage materialize.public.events
  37. Return
  38. Union
  39. Get l0
  40. Map (0)
  41. Union
  42. Negate
  43. Project ()
  44. Get l0
  45. Constant
  46. - ()
  47. Source materialize.public.events
  48. filter=((mz_now() >= numeric_to_mz_timestamp(#1{insert_ms})) AND (mz_now() < numeric_to_mz_timestamp(#2{delete_ms})))
  49. pushdown=((mz_now() >= numeric_to_mz_timestamp(#1{insert_ms})) AND (mz_now() < numeric_to_mz_timestamp(#2{delete_ms})))
  50. Target cluster: quickstart
  51. EOF
  52. query T multiline
  53. EXPLAIN OPTIMIZED PLAN WITH(humanized expressions, filter pushdown) AS VERBOSE TEXT FOR
  54. SELECT content, insert_ms
  55. FROM events
  56. -- The event should appear in only one interval of duration `10000`.
  57. -- The interval begins here ...
  58. WHERE mz_now() >= 10000 * (insert_ms / 10000)
  59. -- ... and ends here.
  60. AND mz_now() < 10000 * (1 + insert_ms / 10000)
  61. ----
  62. Explained Query:
  63. Project (#0{content}, #1{insert_ms})
  64. Filter (mz_now() >= numeric_to_mz_timestamp((10000 * #3))) AND (mz_now() < numeric_to_mz_timestamp((10000 * (1 + #3))))
  65. Map ((#1{insert_ms} / 10000))
  66. ReadStorage materialize.public.events
  67. Source materialize.public.events
  68. filter=((mz_now() < numeric_to_mz_timestamp((10000 * (1 + #3)))) AND (mz_now() >= numeric_to_mz_timestamp((10000 * #3))))
  69. map=((#1{insert_ms} / 10000))
  70. pushdown=((mz_now() < numeric_to_mz_timestamp((10000 * (1 + #3)))) AND (mz_now() >= numeric_to_mz_timestamp((10000 * #3))))
  71. Target cluster: quickstart
  72. EOF
  73. query T multiline
  74. EXPLAIN OPTIMIZED PLAN WITH(humanized expressions, filter pushdown) AS VERBOSE TEXT FOR
  75. SELECT content, insert_ms
  76. FROM events
  77. -- The event should appear in `6` intervals each of width `10000`.
  78. -- The interval begins here ...
  79. WHERE mz_now() >= 10000 * (insert_ms / 10000)
  80. -- ... and ends here.
  81. AND mz_now() < 6 * (10000 + insert_ms / 10000)
  82. ----
  83. Explained Query:
  84. Project (#0{content}, #1{insert_ms})
  85. Filter (mz_now() >= numeric_to_mz_timestamp((10000 * #3))) AND (mz_now() < numeric_to_mz_timestamp((6 * (10000 + #3))))
  86. Map ((#1{insert_ms} / 10000))
  87. ReadStorage materialize.public.events
  88. Source materialize.public.events
  89. filter=((mz_now() < numeric_to_mz_timestamp((6 * (10000 + #3)))) AND (mz_now() >= numeric_to_mz_timestamp((10000 * #3))))
  90. map=((#1{insert_ms} / 10000))
  91. pushdown=((mz_now() < numeric_to_mz_timestamp((6 * (10000 + #3)))) AND (mz_now() >= numeric_to_mz_timestamp((10000 * #3))))
  92. Target cluster: quickstart
  93. EOF
  94. query T multiline
  95. EXPLAIN OPTIMIZED PLAN WITH(humanized expressions, filter pushdown) AS VERBOSE TEXT FOR
  96. SELECT content, insert_ms
  97. FROM events
  98. -- The event should appear inside the interval that begins at
  99. -- `insert_ms` and ends at `insert_ms + 30000`.
  100. -- The interval begins here ..
  101. WHERE mz_now() >= insert_ms
  102. -- ... and ends here.
  103. AND mz_now() < insert_ms + 30000
  104. ----
  105. Explained Query:
  106. Project (#0{content}, #1{insert_ms})
  107. Filter (mz_now() >= numeric_to_mz_timestamp(#1{insert_ms})) AND (mz_now() < numeric_to_mz_timestamp((#1{insert_ms} + 30000)))
  108. ReadStorage materialize.public.events
  109. Source materialize.public.events
  110. filter=((mz_now() < numeric_to_mz_timestamp((#1{insert_ms} + 30000))) AND (mz_now() >= numeric_to_mz_timestamp(#1{insert_ms})))
  111. pushdown=((mz_now() < numeric_to_mz_timestamp((#1{insert_ms} + 30000))) AND (mz_now() >= numeric_to_mz_timestamp(#1{insert_ms})))
  112. Target cluster: quickstart
  113. EOF
  114. query T multiline
  115. EXPLAIN OPTIMIZED PLAN WITH(humanized expressions, filter pushdown) AS VERBOSE TEXT FOR
  116. SELECT content, insert_ms, delete_ms
  117. FROM events
  118. WHERE mz_now() >= insert_ms + 60000
  119. AND mz_now() < delete_ms + 60000;
  120. ----
  121. Explained Query:
  122. Filter (mz_now() < numeric_to_mz_timestamp((#2{delete_ms} + 60000))) AND (mz_now() >= numeric_to_mz_timestamp((#1{insert_ms} + 60000)))
  123. ReadStorage materialize.public.events
  124. Source materialize.public.events
  125. filter=((mz_now() >= numeric_to_mz_timestamp((#1{insert_ms} + 60000))) AND (mz_now() < numeric_to_mz_timestamp((#2{delete_ms} + 60000))))
  126. pushdown=((mz_now() >= numeric_to_mz_timestamp((#1{insert_ms} + 60000))) AND (mz_now() < numeric_to_mz_timestamp((#2{delete_ms} + 60000))))
  127. Target cluster: quickstart
  128. EOF
  129. # Verify explain behaviour for functions with many arguments. In theory, we can't push down
  130. # non-associative functions with long argument lists... but in practice all the functions we
  131. # can push down are also associative, so this is moot. Let's at least check that an associative
  132. # function _does_ report pushdown even when the argument list is long.
  133. query T multiline
  134. EXPLAIN OPTIMIZED PLAN WITH(humanized expressions, filter pushdown) AS VERBOSE TEXT FOR
  135. SELECT content, insert_ms, delete_ms
  136. FROM events
  137. WHERE COALESCE(delete_ms, insert_ms) < mz_now();
  138. ----
  139. Explained Query:
  140. Filter (numeric_to_mz_timestamp(coalesce(#2{delete_ms}, #1{insert_ms})) < mz_now())
  141. ReadStorage materialize.public.events
  142. Source materialize.public.events
  143. filter=((numeric_to_mz_timestamp(coalesce(#2{delete_ms}, #1{insert_ms})) < mz_now()))
  144. pushdown=((numeric_to_mz_timestamp(coalesce(#2{delete_ms}, #1{insert_ms})) < mz_now()))
  145. Target cluster: quickstart
  146. EOF
  147. query T multiline
  148. EXPLAIN OPTIMIZED PLAN WITH(humanized expressions, filter pushdown) AS VERBOSE TEXT FOR
  149. SELECT content, insert_ms, delete_ms
  150. FROM events
  151. WHERE mz_now() < delete_ms + 10000
  152. AND mz_now() < delete_ms + 20000
  153. AND mz_now() < delete_ms + 30000
  154. AND mz_now() < delete_ms + 40000
  155. AND mz_now() < delete_ms + 50000
  156. AND mz_now() < delete_ms + 60000
  157. AND mz_now() < delete_ms + 70000
  158. AND mz_now() < delete_ms + 80000
  159. AND mz_now() < delete_ms + 90000;
  160. ----
  161. Explained Query:
  162. Filter (mz_now() < numeric_to_mz_timestamp((#2{delete_ms} + 10000))) AND (mz_now() < numeric_to_mz_timestamp((#2{delete_ms} + 20000))) AND (mz_now() < numeric_to_mz_timestamp((#2{delete_ms} + 30000))) AND (mz_now() < numeric_to_mz_timestamp((#2{delete_ms} + 40000))) AND (mz_now() < numeric_to_mz_timestamp((#2{delete_ms} + 50000))) AND (mz_now() < numeric_to_mz_timestamp((#2{delete_ms} + 60000))) AND (mz_now() < numeric_to_mz_timestamp((#2{delete_ms} + 70000))) AND (mz_now() < numeric_to_mz_timestamp((#2{delete_ms} + 80000))) AND (mz_now() < numeric_to_mz_timestamp((#2{delete_ms} + 90000)))
  163. ReadStorage materialize.public.events
  164. Source materialize.public.events
  165. filter=((mz_now() < numeric_to_mz_timestamp((#2{delete_ms} + 10000))) AND (mz_now() < numeric_to_mz_timestamp((#2{delete_ms} + 20000))) AND (mz_now() < numeric_to_mz_timestamp((#2{delete_ms} + 30000))) AND (mz_now() < numeric_to_mz_timestamp((#2{delete_ms} + 40000))) AND (mz_now() < numeric_to_mz_timestamp((#2{delete_ms} + 50000))) AND (mz_now() < numeric_to_mz_timestamp((#2{delete_ms} + 60000))) AND (mz_now() < numeric_to_mz_timestamp((#2{delete_ms} + 70000))) AND (mz_now() < numeric_to_mz_timestamp((#2{delete_ms} + 80000))) AND (mz_now() < numeric_to_mz_timestamp((#2{delete_ms} + 90000))))
  166. pushdown=((mz_now() < numeric_to_mz_timestamp((#2{delete_ms} + 10000))) AND (mz_now() < numeric_to_mz_timestamp((#2{delete_ms} + 20000))) AND (mz_now() < numeric_to_mz_timestamp((#2{delete_ms} + 30000))) AND (mz_now() < numeric_to_mz_timestamp((#2{delete_ms} + 40000))) AND (mz_now() < numeric_to_mz_timestamp((#2{delete_ms} + 50000))) AND (mz_now() < numeric_to_mz_timestamp((#2{delete_ms} + 60000))) AND (mz_now() < numeric_to_mz_timestamp((#2{delete_ms} + 70000))) AND (mz_now() < numeric_to_mz_timestamp((#2{delete_ms} + 80000))) AND (mz_now() < numeric_to_mz_timestamp((#2{delete_ms} + 90000))))
  167. Target cluster: quickstart
  168. EOF
  169. statement ok
  170. CREATE TABLE events_timestamped (
  171. content text,
  172. inserted_at timestamp,
  173. deleted_at timestamp
  174. );
  175. query T multiline
  176. EXPLAIN OPTIMIZED PLAN WITH(humanized expressions, filter pushdown) AS VERBOSE TEXT FOR
  177. SELECT content, inserted_at
  178. FROM events_timestamped
  179. WHERE EXTRACT(YEAR FROM inserted_at) = 2021;
  180. ----
  181. Explained Query:
  182. Project (#0{content}, #1{inserted_at})
  183. Filter (2021 = extract_year_ts(#1{inserted_at}))
  184. ReadStorage materialize.public.events_timestamped
  185. Source materialize.public.events_timestamped
  186. filter=((2021 = extract_year_ts(#1{inserted_at})))
  187. pushdown=((2021 = extract_year_ts(#1{inserted_at})))
  188. Target cluster: quickstart
  189. EOF
  190. # Verify that try_parse_monotonic_iso8601_timestamp gets pushdown (the whole
  191. # point of that func)
  192. query T multiline
  193. EXPLAIN OPTIMIZED PLAN WITH(humanized expressions, filter pushdown) AS VERBOSE TEXT FOR
  194. SELECT content, inserted_at
  195. FROM events_timestamped
  196. WHERE mz_now() < try_parse_monotonic_iso8601_timestamp(content);
  197. ----
  198. Explained Query:
  199. Project (#0{content}, #1{inserted_at})
  200. Filter (mz_now() < timestamp_to_mz_timestamp(try_parse_monotonic_iso8601_timestamp(#0{content})))
  201. ReadStorage materialize.public.events_timestamped
  202. Source materialize.public.events_timestamped
  203. filter=((mz_now() < timestamp_to_mz_timestamp(try_parse_monotonic_iso8601_timestamp(#0{content}))))
  204. pushdown=((mz_now() < timestamp_to_mz_timestamp(try_parse_monotonic_iso8601_timestamp(#0{content}))))
  205. Target cluster: quickstart
  206. EOF
  207. # Regression tests for https://github.com/MaterializeInc/database-issues/issues/6640
  208. statement ok
  209. create table t(x int, t timestamp);
  210. query T multiline
  211. EXPLAIN OPTIMIZED PLAN WITH(filter pushdown, humanized expressions) AS VERBOSE TEXT FOR
  212. select * from t
  213. where t < '2023-10-02 15:55:31.918 UTC';
  214. ----
  215. Explained Query:
  216. Filter (#1{t} < 2023-10-02 15:55:31.918)
  217. ReadStorage materialize.public.t
  218. Source materialize.public.t
  219. filter=((#1{t} < 2023-10-02 15:55:31.918))
  220. pushdown=((#1{t} < 2023-10-02 15:55:31.918))
  221. Target cluster: quickstart
  222. EOF
  223. query T multiline
  224. EXPLAIN OPTIMIZED PLAN WITH(filter pushdown, humanized expressions) AS VERBOSE TEXT FOR
  225. select * from t
  226. where case when x=0 then t < '2023-10-02 15:55:31.918 UTC' else t > '2023-10-02 15:55:31.918 UTC' end;
  227. ----
  228. Explained Query:
  229. Filter case when (#0{x} = 0) then (#1{t} < 2023-10-02 15:55:31.918) else (#1{t} > 2023-10-02 15:55:31.918) end
  230. ReadStorage materialize.public.t
  231. Source materialize.public.t
  232. filter=(case when (#0{x} = 0) then (#1{t} < 2023-10-02 15:55:31.918) else (#1{t} > 2023-10-02 15:55:31.918) end)
  233. pushdown=(case when (#0{x} = 0) then (#1{t} < 2023-10-02 15:55:31.918) else (#1{t} > 2023-10-02 15:55:31.918) end)
  234. Target cluster: quickstart
  235. EOF
  236. query T multiline
  237. EXPLAIN OPTIMIZED PLAN WITH(filter pushdown, humanized expressions) AS VERBOSE TEXT FOR
  238. with cte as (
  239. select x, t, case when x=0 then t - INTERVAL '1' day else t - INTERVAL '2' day end as case_statement from t
  240. )
  241. select x, t, case_statement from cte
  242. where case_statement < '2023-10-02 15:55:31.918 UTC';
  243. ----
  244. Explained Query:
  245. Filter (#2 < 2023-10-02 15:55:31.918)
  246. Map ((#1{t} - case when (#0{x} = 0) then 1 day else 2 days end))
  247. ReadStorage materialize.public.t
  248. Source materialize.public.t
  249. filter=(((#1{t} - case when (#0{x} = 0) then 1 day else 2 days end) < 2023-10-02 15:55:31.918))
  250. pushdown=(((#1{t} - case when (#0{x} = 0) then 1 day else 2 days end) < 2023-10-02 15:55:31.918))
  251. Target cluster: quickstart
  252. EOF
  253. query T multiline
  254. EXPLAIN OPTIMIZED PLAN WITH(filter pushdown, humanized expressions) AS VERBOSE TEXT FOR
  255. with cte as (
  256. select x, t, case when x=0 then t - INTERVAL '1' day else t - INTERVAL '2' day end as case_statement from t
  257. )
  258. select x, t from cte
  259. where case_statement < mz_now();
  260. ----
  261. Explained Query:
  262. Filter (timestamp_to_mz_timestamp((#1{t} - case when (#0{x} = 0) then 1 day else 2 days end)) < mz_now())
  263. ReadStorage materialize.public.t
  264. Source materialize.public.t
  265. filter=((timestamp_to_mz_timestamp((#1{t} - case when (#0{x} = 0) then 1 day else 2 days end)) < mz_now()))
  266. pushdown=((timestamp_to_mz_timestamp((#1{t} - case when (#0{x} = 0) then 1 day else 2 days end)) < mz_now()))
  267. Target cluster: quickstart
  268. EOF
  269. # Regression test: should not report pushdown when one case can't be pushed down / might throw an exception.
  270. # (We don't infer a range for the result of EXTRACT, so the overall expression may overflow.)
  271. statement ok
  272. CREATE TABLE items(id int, ship_time timestamp);
  273. query T multiline
  274. EXPLAIN OPTIMIZED PLAN WITH(filter pushdown, humanized expressions) AS VERBOSE TEXT FOR
  275. SELECT * from items
  276. WHERE mz_now() <= date_trunc(
  277. 'month',
  278. ship_time
  279. - (
  280. CASE WHEN EXTRACT(MONTH FROM ship_time) < 6 THEN EXTRACT(MONTH FROM ship_time) + 6 ELSE 0 END
  281. + CASE WHEN EXTRACT(MONTH FROM ship_time) >= 6 THEN EXTRACT(MONTH FROM ship_time) - 6 ELSE 0 END
  282. )
  283. * INTERVAL '1 months'
  284. )
  285. ----
  286. Explained Query:
  287. Project (#0{id}, #1{ship_time})
  288. Filter (mz_now() <= timestamp_to_mz_timestamp(date_trunc_month_ts((#1{ship_time} - (1 month * numeric_to_double((case when (#2 < 6) then (extract_month_ts(#1{ship_time}) + 6) else 0 end + case when (#2 >= 6) then (extract_month_ts(#1{ship_time}) - 6) else 0 end)))))))
  289. Map (extract_month_ts(#1{ship_time}))
  290. ReadStorage materialize.public.items
  291. Source materialize.public.items
  292. filter=((mz_now() <= timestamp_to_mz_timestamp(date_trunc_month_ts((#1{ship_time} - (1 month * numeric_to_double((case when (#2 < 6) then (extract_month_ts(#1{ship_time}) + 6) else 0 end + case when (#2 >= 6) then (extract_month_ts(#1{ship_time}) - 6) else 0 end))))))))
  293. map=(extract_month_ts(#1{ship_time}))
  294. Target cluster: quickstart
  295. EOF
  296. query T multiline
  297. EXPLAIN OPTIMIZED PLAN WITH(filter pushdown, humanized expressions) AS VERBOSE TEXT FOR
  298. SELECT * from items
  299. WHERE CASE WHEN id = 10 THEN EXTRACT(MONTH FROM ship_time) ELSE 0 END < mz_now();
  300. ----
  301. Explained Query:
  302. Filter (numeric_to_mz_timestamp(case when (#0{id} = 10) then extract_month_ts(#1{ship_time}) else 0 end) < mz_now())
  303. ReadStorage materialize.public.items
  304. Source materialize.public.items
  305. filter=((numeric_to_mz_timestamp(case when (#0{id} = 10) then extract_month_ts(#1{ship_time}) else 0 end) < mz_now()))
  306. Target cluster: quickstart
  307. EOF
  308. query T multiline
  309. EXPLAIN OPTIMIZED PLAN WITH(filter pushdown, humanized expressions) AS VERBOSE TEXT FOR
  310. SELECT * from items
  311. WHERE CASE WHEN EXTRACT(MONTH FROM ship_time) >= 6 THEN 12 ELSE 0 END < mz_now();
  312. ----
  313. Explained Query:
  314. Filter (integer_to_mz_timestamp(case when (extract_month_ts(#1{ship_time}) >= 6) then 12 else 0 end) < mz_now())
  315. ReadStorage materialize.public.items
  316. Source materialize.public.items
  317. filter=((integer_to_mz_timestamp(case when (extract_month_ts(#1{ship_time}) >= 6) then 12 else 0 end) < mz_now()))
  318. pushdown=((integer_to_mz_timestamp(case when (extract_month_ts(#1{ship_time}) >= 6) then 12 else 0 end) < mz_now()))
  319. Target cluster: quickstart
  320. EOF