reduce_mfp.slt 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  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. #
  10. # Test proper fusion of MFPs in Reduce.
  11. # PR https://github.com/MaterializeInc/materialize/pull/23197
  12. #
  13. mode cockroach
  14. simple conn=mz_system,user=mz_system
  15. ALTER SYSTEM SET enable_reduce_mfp_fusion TO true;
  16. ----
  17. COMPLETE 0
  18. statement ok
  19. CREATE TABLE t (a int, b int);
  20. statement ok
  21. INSERT INTO t VALUES (1, 1), (1, 2), (1, 3), (2, 1), (2, 2), (3, 1);
  22. # Illustrates a special-case MFP where we can completely absorb all
  23. # components, including a projection.
  24. statement ok
  25. CREATE MATERIALIZED VIEW mv_fusable_mfp_accumulable AS
  26. SELECT a, SUM(b)
  27. FROM t
  28. GROUP BY a
  29. HAVING ((COUNT(b) + 1) - a) > 2 AND (COUNT(b) + 1) / (1 + a) >= 1;
  30. query II
  31. SELECT * FROM mv_fusable_mfp_accumulable;
  32. ----
  33. 1 6
  34. query T multiline
  35. EXPLAIN PHYSICAL PLAN AS VERBOSE TEXT FOR
  36. MATERIALIZED VIEW mv_fusable_mfp_accumulable;
  37. ----
  38. materialize.public.mv_fusable_mfp_accumulable:
  39. Reduce::Accumulable
  40. simple_aggrs[0]=(0, 0, sum(#1{b}))
  41. simple_aggrs[1]=(1, 1, count(#1{b}))
  42. val_plan
  43. project=(#1, #1)
  44. key_plan
  45. project=(#0)
  46. mfp_after
  47. project=(#0, #1)
  48. filter=(((#3 - integer_to_bigint(#0{a})) > 2) AND ((#3 / integer_to_bigint((1 + #0{a}))) >= 1))
  49. map=((#2{"?column?"} + 1))
  50. Get::PassArrangements materialize.public.t
  51. raw=true
  52. Source materialize.public.t
  53. Target cluster: quickstart
  54. EOF
  55. # Illustrates a complex MFP scenario with all three components
  56. # active in the fused MFP.
  57. statement ok
  58. CREATE MATERIALIZED VIEW mv_complex_mfp_accumulable AS
  59. SELECT a, SUM(b) + 1
  60. FROM t
  61. GROUP BY a
  62. HAVING ((COUNT(b) + 1) - a) > 2 AND (COUNT(b) + 1) / (1 + a) >= 1;
  63. query II
  64. SELECT * FROM mv_complex_mfp_accumulable;
  65. ----
  66. 1 7
  67. query T multiline
  68. EXPLAIN PHYSICAL PLAN AS VERBOSE TEXT FOR
  69. MATERIALIZED VIEW mv_complex_mfp_accumulable;
  70. ----
  71. materialize.public.mv_complex_mfp_accumulable:
  72. Mfp
  73. project=(#0, #3)
  74. map=((#1{"?column?"} + 1))
  75. input_key=#0
  76. Reduce::Accumulable
  77. simple_aggrs[0]=(0, 0, sum(#1{b}))
  78. simple_aggrs[1]=(1, 1, count(#1{b}))
  79. val_plan
  80. project=(#1, #1)
  81. key_plan
  82. project=(#0)
  83. mfp_after
  84. filter=(((#3 - integer_to_bigint(#0{a})) > 2) AND ((#3 / integer_to_bigint((1 + #0{a}))) >= 1))
  85. map=((#2{"?column?"} + 1))
  86. Get::PassArrangements materialize.public.t
  87. raw=true
  88. Source materialize.public.t
  89. Target cluster: quickstart
  90. EOF
  91. # Check that we treat errors properly.
  92. statement ok
  93. INSERT INTO t VALUES (-1, 3);
  94. query error division by zero
  95. SELECT * FROM mv_fusable_mfp_accumulable;
  96. query error division by zero
  97. SELECT * FROM mv_complex_mfp_accumulable;
  98. statement ok
  99. DELETE FROM t WHERE a = -1;
  100. query II
  101. SELECT * FROM mv_fusable_mfp_accumulable;
  102. ----
  103. 1 6
  104. query II
  105. SELECT * FROM mv_complex_mfp_accumulable;
  106. ----
  107. 1 7
  108. # We test variations of the scenario above to cover reduction types.
  109. statement ok
  110. CREATE MATERIALIZED VIEW mv_complex_mfp_basic_single AS
  111. SELECT a, LIST_AGG(b ORDER BY b DESC)::text
  112. FROM t
  113. GROUP BY a
  114. HAVING
  115. ((LIST_AGG(b ORDER BY b DESC)[1] + 1) - a) > 2 AND
  116. (LIST_AGG(b ORDER BY b DESC)[1] + 1) / (1 + a) >= 1;
  117. query IT
  118. SELECT * FROM mv_complex_mfp_basic_single;
  119. ----
  120. 1 {3,2,1}
  121. statement ok
  122. INSERT INTO t VALUES (-1, 3);
  123. query error division by zero
  124. SELECT * FROM mv_complex_mfp_basic_single;
  125. statement ok
  126. DELETE FROM t WHERE a = -1;
  127. query IT
  128. SELECT * FROM mv_complex_mfp_basic_single;
  129. ----
  130. 1 {3,2,1}
  131. statement ok
  132. CREATE MATERIALIZED VIEW mv_complex_mfp_basic_distinct_single AS
  133. SELECT a, LIST_AGG(DISTINCT b ORDER BY b DESC)::text
  134. FROM t
  135. GROUP BY a
  136. HAVING
  137. ((LIST_AGG(DISTINCT b ORDER BY b DESC)[1] + 1) - a) > 2 AND
  138. (LIST_AGG(DISTINCT b ORDER BY b DESC)[1] + 1) / (1 + a) >= 1;
  139. query IT
  140. SELECT * FROM mv_complex_mfp_basic_distinct_single;
  141. ----
  142. 1 {3,2,1}
  143. statement ok
  144. INSERT INTO t VALUES (-1, 3);
  145. query error division by zero
  146. SELECT * FROM mv_complex_mfp_basic_distinct_single;
  147. statement ok
  148. DELETE FROM t WHERE a = -1;
  149. query IT
  150. SELECT * FROM mv_complex_mfp_basic_distinct_single;
  151. ----
  152. 1 {3,2,1}
  153. statement ok
  154. CREATE MATERIALIZED VIEW mv_complex_mfp_basic_multiple AS
  155. SELECT a, LIST_AGG(b ORDER BY b DESC)::text
  156. FROM t
  157. GROUP BY a
  158. HAVING
  159. ((ARRAY_AGG(b ORDER BY b DESC)[1] + 1) - a) > 2 AND
  160. (ARRAY_AGG(b ORDER BY b DESC)[1] + 1) / (1 + a) >= 1;
  161. query IT
  162. SELECT * FROM mv_complex_mfp_basic_multiple;
  163. ----
  164. 1 {3,2,1}
  165. statement ok
  166. INSERT INTO t VALUES (-1, 3);
  167. query error division by zero
  168. SELECT * FROM mv_complex_mfp_basic_multiple;
  169. statement ok
  170. DELETE FROM t WHERE a = -1;
  171. query IT
  172. SELECT * FROM mv_complex_mfp_basic_multiple;
  173. ----
  174. 1 {3,2,1}
  175. statement ok
  176. CREATE MATERIALIZED VIEW mv_complex_mfp_bucketed AS
  177. SELECT a, MAX(b) + 1
  178. FROM t
  179. GROUP BY a
  180. HAVING ((MAX(b) + 1) - a) > 2 AND (MAX(b) + 1) / (1 + a) >= 1;
  181. query II
  182. SELECT * FROM mv_complex_mfp_bucketed;
  183. ----
  184. 1 4
  185. # Note we use a one-shot SELECT to cover the monotonic case.
  186. query II
  187. SELECT a, MAX(b) + 1
  188. FROM t
  189. GROUP BY a
  190. HAVING ((MAX(b) + 1) - a) > 2 AND (MAX(b) + 1) / (1 + a) >= 1;
  191. ----
  192. 1 4
  193. statement ok
  194. INSERT INTO t VALUES (-1, 3);
  195. query error division by zero
  196. SELECT * FROM mv_complex_mfp_bucketed;
  197. query error division by zero
  198. SELECT a, MAX(b) + 1
  199. FROM t
  200. GROUP BY a
  201. HAVING ((MAX(b) + 1) - a) > 2 AND (MAX(b) + 1) / (1 + a) >= 1;
  202. statement ok
  203. DELETE FROM t WHERE a = -1;
  204. query II
  205. SELECT * FROM mv_complex_mfp_bucketed;
  206. ----
  207. 1 4
  208. query II
  209. SELECT a, MAX(b) + 1
  210. FROM t
  211. GROUP BY a
  212. HAVING ((MAX(b) + 1) - a) > 2 AND (MAX(b) + 1) / (1 + a) >= 1;
  213. ----
  214. 1 4
  215. statement ok
  216. CREATE MATERIALIZED VIEW mv_complex_mfp_collation AS
  217. SELECT a, MAX(b) + 1
  218. FROM t
  219. GROUP BY a
  220. HAVING ((COUNT(b) + 1) - a) > 2 AND (COUNT(b) + 1) / (1 + a) >= 1;
  221. query II
  222. SELECT * FROM mv_complex_mfp_collation;
  223. ----
  224. 1 4
  225. statement ok
  226. INSERT INTO t VALUES (-1, 3);
  227. query error division by zero
  228. SELECT * FROM mv_complex_mfp_collation;
  229. statement ok
  230. DELETE FROM t WHERE a = -1;
  231. query II
  232. SELECT * FROM mv_complex_mfp_collation;
  233. ----
  234. 1 4
  235. # NOTE(vmarcos): Even though placement of an Mfp that has parts that can be
  236. # fused on top of a Reduce::Distinct is valid LIR, we should not at present produce
  237. # this pattern via SQL. To see why, note that if the MFP has parts that could be fused,
  238. # then it must preserve the reduction key, i.e., all columns for the distinct, and
  239. # the fusable parts need to be: (a) free of temporal filters; (b) only contain map
  240. # and filter (i.e., essentially be a predicate). So, these fusable parts could just as
  241. # well be applied to the input to the Reduce::Distinct, and the optimizer will just
  242. # perform predicate pushdown to filter the input before it gets arranged. Additionally,
  243. # if it were the case that we would lift the predicate to enable reuse, then that would
  244. # mean that we could not fuse it into the reduction anyway.