mzcompose.py 83 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776
  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. Tests with limited amount of memory, makes sure that the scenarios keep working
  11. and do not regress. Contains tests for large data ingestions.
  12. """
  13. import argparse
  14. import math
  15. from dataclasses import dataclass
  16. from string import ascii_lowercase
  17. from textwrap import dedent
  18. from materialize import buildkite
  19. from materialize.buildkite import shard_list
  20. from materialize.mzcompose.composition import Composition, WorkflowArgumentParser
  21. from materialize.mzcompose.services.clusterd import Clusterd
  22. from materialize.mzcompose.services.materialized import Materialized
  23. from materialize.mzcompose.services.mysql import MySql
  24. from materialize.mzcompose.services.mz import Mz
  25. from materialize.mzcompose.services.postgres import Postgres
  26. from materialize.mzcompose.services.redpanda import Redpanda
  27. from materialize.mzcompose.services.testdrive import Testdrive
  28. from materialize.test_analytics.config.test_analytics_db_config import (
  29. create_dummy_test_analytics_config,
  30. create_test_analytics_config,
  31. )
  32. from materialize.test_analytics.data.bounded_memory.bounded_memory_minimal_search_storage import (
  33. BOUNDED_MEMORY_STATUS_CONFIGURED,
  34. BOUNDED_MEMORY_STATUS_FAILURE,
  35. BOUNDED_MEMORY_STATUS_SUCCESS,
  36. BoundedMemoryMinimalSearchEntry,
  37. )
  38. from materialize.test_analytics.test_analytics_db import TestAnalyticsDb
  39. # Those defaults have been carefully chosen to avoid known OOMs
  40. # such as materialize#15093 and database-issues#4297 while hopefully catching any further
  41. # regressions in memory usage
  42. PAD_LEN = 1024
  43. STRING_PAD = "x" * PAD_LEN
  44. REPEAT = 16 * 1024
  45. ITERATIONS = 128
  46. BOUNDED_MEMORY_FRAMEWORK_VERSION = "1.0.0"
  47. SERVICES = [
  48. Materialized(), # overridden below
  49. Testdrive(
  50. no_reset=True,
  51. seed=1,
  52. default_timeout="3600s",
  53. entrypoint_extra=[
  54. f"--var=default-storage-size={Materialized.Size.DEFAULT_SIZE}-1",
  55. f"--var=mysql-root-password={MySql.DEFAULT_ROOT_PASSWORD}",
  56. ],
  57. ),
  58. Redpanda(),
  59. Postgres(),
  60. MySql(),
  61. Clusterd(),
  62. Mz(app_password=""),
  63. ]
  64. @dataclass
  65. class Scenario:
  66. name: str
  67. pre_restart: str
  68. post_restart: str
  69. materialized_memory: str
  70. clusterd_memory: str
  71. disabled: bool = False
  72. class PgCdcScenario(Scenario):
  73. PG_SETUP = dedent(
  74. """
  75. > CREATE SECRET pgpass AS 'postgres'
  76. > CREATE CONNECTION pg FOR POSTGRES
  77. HOST postgres,
  78. DATABASE postgres,
  79. USER postgres,
  80. PASSWORD SECRET pgpass
  81. $ postgres-execute connection=postgres://postgres:postgres@postgres
  82. ALTER USER postgres WITH replication;
  83. CREATE TABLE t1 (f1 SERIAL PRIMARY KEY, f2 INTEGER DEFAULT 0, f3 TEXT);
  84. ALTER TABLE t1 REPLICA IDENTITY FULL;
  85. CREATE PUBLICATION mz_source FOR ALL TABLES;
  86. """
  87. )
  88. MZ_SETUP = dedent(
  89. """
  90. > CREATE SOURCE mz_source
  91. IN CLUSTER clusterd
  92. FROM POSTGRES CONNECTION pg (PUBLICATION 'mz_source');
  93. > CREATE TABLE t1 FROM SOURCE mz_source (REFERENCE t1);
  94. > CREATE MATERIALIZED VIEW v1 AS SELECT COUNT(*) FROM t1;
  95. """
  96. )
  97. class MySqlCdcScenario(Scenario):
  98. MYSQL_SETUP = dedent(
  99. f"""
  100. > CREATE SECRET mysqlpass AS '${{arg.mysql-root-password}}'
  101. > CREATE CONNECTION mysql_conn TO MYSQL (
  102. HOST mysql,
  103. USER root,
  104. PASSWORD SECRET mysqlpass
  105. )
  106. $ mysql-connect name=mysql url=mysql://root@mysql password=${{arg.mysql-root-password}}
  107. $ mysql-execute name=mysql
  108. # needed for MySQL 5.7
  109. SET GLOBAL max_allowed_packet=67108864;
  110. # reconnect
  111. $ mysql-connect name=mysql url=mysql://root@mysql password=${{arg.mysql-root-password}}
  112. $ mysql-execute name=mysql
  113. DROP DATABASE IF EXISTS public;
  114. CREATE DATABASE public;
  115. USE public;
  116. SET @i:=0;
  117. CREATE TABLE series_helper (i INT);
  118. INSERT INTO series_helper (i) SELECT @i:=@i+1 FROM mysql.time_zone t1, mysql.time_zone t2 LIMIT {REPEAT};
  119. CREATE TABLE t1 (f1 SERIAL PRIMARY KEY, f2 INTEGER DEFAULT 0, f3 TEXT);
  120. """
  121. )
  122. MZ_SETUP = dedent(
  123. """
  124. > CREATE SOURCE mz_source
  125. IN CLUSTER clusterd
  126. FROM MYSQL CONNECTION mysql_conn;
  127. > CREATE TABLE t1 FROM SOURCE mz_source (REFERENCE public.t1);
  128. > CREATE MATERIALIZED VIEW v1 AS SELECT COUNT(*) FROM t1;
  129. """
  130. )
  131. class KafkaScenario(Scenario):
  132. SCHEMAS = dedent(
  133. """
  134. $ set key-schema={
  135. "type": "string"
  136. }
  137. $ set value-schema={
  138. "type" : "record",
  139. "name" : "test",
  140. "fields" : [
  141. {"name":"f1", "type":"string"}
  142. ]
  143. }
  144. """
  145. )
  146. CONNECTIONS = dedent(
  147. """
  148. $ kafka-create-topic topic=topic1
  149. $ kafka-ingest format=avro key-format=avro topic=topic1 schema=${value-schema} key-schema=${key-schema}
  150. "AAA" {"f1": "START MARKER"}
  151. > CREATE CONNECTION IF NOT EXISTS csr_conn
  152. FOR CONFLUENT SCHEMA REGISTRY
  153. URL '${testdrive.schema-registry-url}';
  154. > CREATE CONNECTION IF NOT EXISTS kafka_conn
  155. FOR KAFKA BROKER '${testdrive.kafka-addr}', SECURITY PROTOCOL PLAINTEXT;
  156. """
  157. )
  158. SOURCE = dedent(
  159. """
  160. > CREATE SOURCE s1
  161. IN CLUSTER clusterd
  162. FROM KAFKA CONNECTION kafka_conn (TOPIC 'testdrive-topic1-${testdrive.seed}');
  163. > CREATE TABLE s1_tbl FROM SOURCE s1 (REFERENCE "testdrive-topic1-${testdrive.seed}")
  164. FORMAT AVRO USING CONFLUENT SCHEMA REGISTRY CONNECTION csr_conn
  165. ENVELOPE UPSERT;
  166. > CREATE MATERIALIZED VIEW v1 AS SELECT COUNT(*) FROM s1_tbl;
  167. """
  168. )
  169. END_MARKER = dedent(
  170. """
  171. $ kafka-ingest format=avro key-format=avro topic=topic1 schema=${value-schema} key-schema=${key-schema}
  172. "ZZZ" {"f1": "END MARKER"}
  173. """
  174. )
  175. POST_RESTART = dedent(
  176. f"""
  177. # Delete all rows except markers
  178. $ kafka-ingest format=avro key-format=avro topic=topic1 schema=${{value-schema}} key-schema=${{key-schema}} repeat={REPEAT}
  179. "${{kafka-ingest.iteration}}"
  180. $ kafka-ingest format=avro key-format=avro topic=topic1 schema=${{value-schema}} key-schema=${{key-schema}} repeat={REPEAT}
  181. "MMM"
  182. # Expect that only markers are left
  183. > SELECT * FROM v1;
  184. 2
  185. """
  186. )
  187. SCENARIOS = [
  188. PgCdcScenario(
  189. name="pg-cdc-snapshot",
  190. pre_restart=PgCdcScenario.PG_SETUP
  191. + "$ postgres-execute connection=postgres://postgres:postgres@postgres\n"
  192. + "\n".join(
  193. [
  194. dedent(
  195. f"""
  196. INSERT INTO t1 (f3) SELECT '{i}' || REPEAT('a', {PAD_LEN}) FROM generate_series(1, {REPEAT});
  197. """
  198. )
  199. for i in range(0, ITERATIONS * 10)
  200. ]
  201. )
  202. + PgCdcScenario.MZ_SETUP
  203. + dedent(
  204. f"""
  205. > SELECT * FROM v1; /* expect {ITERATIONS * 10 * REPEAT} */
  206. {ITERATIONS * 10 * REPEAT}
  207. > SELECT COUNT(*) FROM t1; /* expect {ITERATIONS * 10 * REPEAT} */
  208. {ITERATIONS * 10 * REPEAT}
  209. """
  210. ),
  211. post_restart=dedent(
  212. f"""
  213. # We do not do DELETE post-restart, as it will cause postgres to go out of disk
  214. > SELECT * FROM v1; /* expect {ITERATIONS * 10 * REPEAT} */
  215. {ITERATIONS * 10 * REPEAT}
  216. > SELECT COUNT(*) FROM t1; /* expect {ITERATIONS * 10 * REPEAT} */
  217. {ITERATIONS * 10 * REPEAT}
  218. """
  219. ),
  220. materialized_memory="4.5Gb",
  221. clusterd_memory="1Gb",
  222. ),
  223. PgCdcScenario(
  224. name="pg-cdc-update",
  225. pre_restart=PgCdcScenario.PG_SETUP
  226. + dedent(
  227. f"""
  228. $ postgres-execute connection=postgres://postgres:postgres@postgres
  229. INSERT INTO t1 (f3) VALUES ('START');
  230. INSERT INTO t1 (f3) SELECT REPEAT('a', {PAD_LEN}) FROM generate_series(1, {REPEAT});
  231. """
  232. )
  233. + PgCdcScenario.MZ_SETUP
  234. + "\n".join(
  235. [
  236. dedent(
  237. """
  238. $ postgres-execute connection=postgres://postgres:postgres@postgres
  239. UPDATE t1 SET f2 = f2 + 1;
  240. """
  241. )
  242. for letter in ascii_lowercase[:ITERATIONS]
  243. ]
  244. )
  245. + dedent(
  246. f"""
  247. $ postgres-execute connection=postgres://postgres:postgres@postgres
  248. INSERT INTO t1 (f3) VALUES ('END');
  249. > SELECT * FROM v1 /* expect: {REPEAT + 2} */;
  250. {REPEAT + 2}
  251. > SELECT COUNT(*) FROM t1 /* expect: {REPEAT + 2} */;
  252. {REPEAT + 2}
  253. """
  254. ),
  255. post_restart=dedent(
  256. """
  257. $ postgres-execute connection=postgres://postgres:postgres@postgres
  258. DELETE FROM t1;
  259. > SELECT * FROM v1;
  260. 0
  261. > SELECT COUNT(*) FROM t1;
  262. 0
  263. """
  264. ),
  265. materialized_memory="4.5Gb",
  266. clusterd_memory="3.5Gb",
  267. ),
  268. Scenario(
  269. name="pg-cdc-gh-15044",
  270. pre_restart=dedent(
  271. f"""
  272. > CREATE SECRET pgpass AS 'postgres'
  273. > CREATE CONNECTION pg FOR POSTGRES
  274. HOST postgres,
  275. DATABASE postgres,
  276. USER postgres,
  277. PASSWORD SECRET pgpass
  278. # Insert data pre-snapshot
  279. $ postgres-execute connection=postgres://postgres:postgres@postgres
  280. ALTER USER postgres WITH replication;
  281. DROP SCHEMA IF EXISTS public CASCADE;
  282. DROP PUBLICATION IF EXISTS mz_source;
  283. CREATE SCHEMA public;
  284. CREATE TABLE t1 (f1 SERIAL PRIMARY KEY, f2 INTEGER DEFAULT 0, f3 TEXT);
  285. ALTER TABLE t1 REPLICA IDENTITY FULL;
  286. INSERT INTO t1 (f3) SELECT REPEAT('a', 1024 * 1024) FROM generate_series(1, 16);
  287. CREATE PUBLICATION mz_source FOR ALL TABLES;
  288. > CREATE SOURCE mz_source
  289. FROM POSTGRES CONNECTION pg (PUBLICATION 'mz_source');
  290. > CREATE TABLE t1 FROM SOURCE mz_source (REFERENCE t1);
  291. > SELECT COUNT(*) > 0 FROM t1;
  292. true
  293. # > CREATE MATERIALIZED VIEW v1 AS SELECT f1 + 1, f2 FROM t1;
  294. > CREATE MATERIALIZED VIEW v2 AS SELECT COUNT(*) FROM t1;
  295. # Update data post-snapshot
  296. $ postgres-execute connection=postgres://postgres:postgres@postgres
  297. {'UPDATE t1 SET f2 = f2 + 1;' * 300}
  298. INSERT INTO t1 (f3) VALUES ('eof');
  299. > SELECT * FROM v2;
  300. 17
  301. > SELECT COUNT(*) FROM t2;
  302. """
  303. ),
  304. post_restart=dedent(
  305. """
  306. > SELECT * FROM v2;
  307. 17
  308. > SELECT COUNT(*) FROM t2;
  309. 0
  310. $ postgres-execute connection=postgres://postgres:postgres@postgres
  311. DELETE FROM t1;
  312. > SELECT * FROM v2;
  313. 0
  314. > SELECT COUNT(*) FROM t2;
  315. 0
  316. """
  317. ),
  318. materialized_memory="8Gb",
  319. clusterd_memory="6Gb",
  320. disabled=True,
  321. ),
  322. PgCdcScenario(
  323. name="pg-cdc-large-tx",
  324. pre_restart=PgCdcScenario.PG_SETUP
  325. + PgCdcScenario.MZ_SETUP
  326. + "$ postgres-execute connection=postgres://postgres:postgres@postgres\n"
  327. + "BEGIN;\n"
  328. + "\n".join(
  329. [
  330. dedent(
  331. f"""
  332. INSERT INTO t1 (f3) SELECT '{i}' || REPEAT('a', {PAD_LEN}) FROM generate_series(1, {int(REPEAT / 16)});
  333. """
  334. )
  335. for i in range(0, ITERATIONS * 20)
  336. ]
  337. )
  338. + "COMMIT;\n"
  339. + dedent(
  340. f"""
  341. > SELECT * FROM v1; /* expect {int(ITERATIONS * 20 * REPEAT / 16)} */
  342. {int(ITERATIONS * 20 * REPEAT / 16)}
  343. > SELECT COUNT(*) FROM t1; /* expect {int(ITERATIONS * 20 * REPEAT / 16)} */
  344. {int(ITERATIONS * 20 * REPEAT / 16)}
  345. """
  346. ),
  347. post_restart=dedent(
  348. f"""
  349. > SELECT * FROM v1; /* expect {int(ITERATIONS * 20 * REPEAT / 16)} */
  350. {int(ITERATIONS * 20 * REPEAT / 16)}
  351. > SELECT COUNT(*) FROM t1; /* expect {int(ITERATIONS * 20 * REPEAT / 16)} */
  352. {int(ITERATIONS * 20 * REPEAT / 16)}
  353. $ postgres-execute connection=postgres://postgres:postgres@postgres
  354. DELETE FROM t1;
  355. > SELECT * FROM v1;
  356. 0
  357. > SELECT COUNT(*) FROM t1;
  358. 0
  359. """
  360. ),
  361. materialized_memory="4.5Gb",
  362. # TODO: Reduce to 1Gb when https://github.com/MaterializeInc/database-issues/issues/9515 is fixed
  363. clusterd_memory="2Gb",
  364. ),
  365. MySqlCdcScenario(
  366. name="mysql-cdc-snapshot",
  367. pre_restart=MySqlCdcScenario.MYSQL_SETUP
  368. + "$ mysql-execute name=mysql\n"
  369. + "\n".join(
  370. [
  371. dedent(
  372. f"""
  373. INSERT INTO t1 (f3) SELECT CONCAT('{i}', REPEAT('a', {PAD_LEN})) FROM series_helper;
  374. """
  375. )
  376. for i in range(0, ITERATIONS)
  377. ]
  378. )
  379. + MySqlCdcScenario.MZ_SETUP
  380. + dedent(
  381. f"""
  382. > SELECT * FROM v1; /* expect {ITERATIONS * REPEAT} */
  383. {ITERATIONS * REPEAT}
  384. > SELECT COUNT(*) FROM t1; /* expect {ITERATIONS * REPEAT} */
  385. {ITERATIONS * REPEAT}
  386. """
  387. ),
  388. post_restart=dedent(
  389. f"""
  390. > SELECT * FROM v1; /* expect {ITERATIONS * REPEAT} */
  391. {ITERATIONS * REPEAT}
  392. > SELECT COUNT(*) FROM t1; /* expect {ITERATIONS * REPEAT} */
  393. {ITERATIONS * REPEAT}
  394. $ mysql-connect name=mysql url=mysql://root@mysql password=${{arg.mysql-root-password}}
  395. $ mysql-execute name=mysql
  396. USE public;
  397. DELETE FROM t1;
  398. > SELECT * FROM v1;
  399. 0
  400. > SELECT COUNT(*) FROM t1;
  401. 0
  402. """
  403. ),
  404. materialized_memory="4.5Gb",
  405. clusterd_memory="3.5Gb",
  406. ),
  407. MySqlCdcScenario(
  408. name="mysql-cdc-update",
  409. pre_restart=MySqlCdcScenario.MYSQL_SETUP
  410. + dedent(
  411. f"""
  412. $ mysql-execute name=mysql
  413. INSERT INTO t1 (f3) VALUES ('START');
  414. INSERT INTO t1 (f3) SELECT REPEAT('a', {PAD_LEN}) FROM series_helper;
  415. """
  416. )
  417. + MySqlCdcScenario.MZ_SETUP
  418. + "\n".join(
  419. [
  420. dedent(
  421. """
  422. $ mysql-execute name=mysql
  423. UPDATE t1 SET f2 = f2 + 1;
  424. """
  425. )
  426. for letter in ascii_lowercase[:ITERATIONS]
  427. ]
  428. )
  429. + dedent(
  430. f"""
  431. $ mysql-execute name=mysql
  432. INSERT INTO t1 (f3) VALUES ('END');
  433. > SELECT * FROM v1 /* expect: {REPEAT + 2} */;
  434. {REPEAT + 2}
  435. > SELECT COUNT(*) FROM t1 /* expect: {REPEAT + 2} */;
  436. {REPEAT + 2}
  437. """
  438. ),
  439. post_restart=dedent(
  440. """
  441. $ mysql-connect name=mysql url=mysql://root@mysql password=${arg.mysql-root-password}
  442. $ mysql-execute name=mysql
  443. USE public;
  444. DELETE FROM t1;
  445. > SELECT * FROM v1;
  446. 0
  447. > SELECT COUNT(*) FROM t1;
  448. 0
  449. """
  450. ),
  451. materialized_memory="4.5Gb",
  452. clusterd_memory="3.5Gb",
  453. ),
  454. MySqlCdcScenario(
  455. name="mysql-cdc-large-tx",
  456. pre_restart=MySqlCdcScenario.MYSQL_SETUP
  457. + MySqlCdcScenario.MZ_SETUP
  458. + "$ mysql-execute name=mysql\n"
  459. + "SET AUTOCOMMIT = FALSE;\n"
  460. + "\n".join(
  461. [
  462. dedent(
  463. f"""
  464. INSERT INTO t1 (f3) SELECT CONCAT('{i}', REPEAT('a', {PAD_LEN})) FROM series_helper LIMIT {int(REPEAT / 128)};
  465. """
  466. )
  467. for i in range(0, ITERATIONS * 10)
  468. ]
  469. )
  470. + "COMMIT;\n"
  471. + dedent(
  472. f"""
  473. > SELECT * FROM v1; /* expect {int(ITERATIONS * 10) * int(REPEAT / 128)} */
  474. {int(ITERATIONS * 10) * int(REPEAT / 128)}
  475. > SELECT COUNT(*) FROM t1; /* expect {int(ITERATIONS * 10) * int(REPEAT / 128)} */
  476. {int(ITERATIONS * 10) * int(REPEAT / 128)}
  477. """
  478. ),
  479. post_restart=dedent(
  480. f"""
  481. > SELECT * FROM v1; /* expect {int(ITERATIONS * 10) * int(REPEAT / 128)} */
  482. {int(ITERATIONS * 10) * int(REPEAT / 128)}
  483. > SELECT COUNT(*) FROM t1; /* expect {int(ITERATIONS * 10) * int(REPEAT / 128)} */
  484. {int(ITERATIONS * 10) * int(REPEAT / 128)}
  485. $ mysql-connect name=mysql url=mysql://root@mysql password=${{arg.mysql-root-password}}
  486. $ mysql-execute name=mysql
  487. USE public;
  488. DELETE FROM t1;
  489. > SELECT * FROM v1;
  490. 0
  491. > SELECT COUNT(*) FROM t1;
  492. 0
  493. """
  494. ),
  495. materialized_memory="3.5Gb",
  496. clusterd_memory="8.5Gb",
  497. ),
  498. KafkaScenario(
  499. name="upsert-snapshot",
  500. pre_restart=KafkaScenario.SCHEMAS
  501. + KafkaScenario.CONNECTIONS
  502. + "\n".join(
  503. [
  504. dedent(
  505. f"""
  506. $ kafka-ingest format=avro key-format=avro topic=topic1 schema=${{value-schema}} key-schema=${{key-schema}} repeat={REPEAT}
  507. "MMM" {{"f1": "{i}{STRING_PAD}"}}
  508. """
  509. )
  510. for i in range(0, ITERATIONS)
  511. ]
  512. )
  513. + KafkaScenario.END_MARKER
  514. # Ensure this config works.
  515. + dedent(
  516. """
  517. $ postgres-connect name=mz_system url=postgres://mz_system:materialize@${testdrive.materialize-internal-sql-addr}
  518. $ postgres-execute connection=mz_system
  519. ALTER SYSTEM SET storage_upsert_max_snapshot_batch_buffering = 2;
  520. """
  521. )
  522. + KafkaScenario.SOURCE
  523. + dedent(
  524. """
  525. # Expect all ingested data + two MARKERs
  526. > SELECT * FROM v1;
  527. 3
  528. > SELECT COUNT(*) FROM s1_tbl;
  529. 3
  530. """
  531. ),
  532. post_restart=KafkaScenario.SCHEMAS + KafkaScenario.POST_RESTART,
  533. materialized_memory="2Gb",
  534. clusterd_memory="3.5Gb",
  535. ),
  536. # Perform updates while the source is ingesting
  537. KafkaScenario(
  538. name="upsert-update",
  539. pre_restart=KafkaScenario.SCHEMAS
  540. + KafkaScenario.CONNECTIONS
  541. + KafkaScenario.SOURCE
  542. + "\n".join(
  543. [
  544. dedent(
  545. f"""
  546. $ kafka-ingest format=avro key-format=avro topic=topic1 schema=${{value-schema}} key-schema=${{key-schema}} repeat={REPEAT}
  547. "${{kafka-ingest.iteration}}" {{"f1": "{i}{STRING_PAD}"}}
  548. """
  549. )
  550. for i in range(0, ITERATIONS)
  551. ]
  552. )
  553. + KafkaScenario.END_MARKER
  554. + dedent(
  555. f"""
  556. # Expect all ingested data + two MARKERs
  557. > SELECT * FROM v1;
  558. {REPEAT + 2}
  559. > SELECT COUNT(*) FROM s1_tbl;
  560. {REPEAT + 2}
  561. """
  562. ),
  563. post_restart=KafkaScenario.SCHEMAS + KafkaScenario.POST_RESTART,
  564. materialized_memory="4.5Gb",
  565. clusterd_memory="3.5Gb",
  566. ),
  567. # Perform inserts+deletes while the source is ingesting
  568. KafkaScenario(
  569. name="upsert-insert-delete",
  570. pre_restart=KafkaScenario.SCHEMAS
  571. + KafkaScenario.CONNECTIONS
  572. + KafkaScenario.SOURCE
  573. + "\n".join(
  574. [
  575. dedent(
  576. f"""
  577. $ kafka-ingest format=avro key-format=avro topic=topic1 schema=${{value-schema}} key-schema=${{key-schema}} repeat={REPEAT}
  578. "${{kafka-ingest.iteration}}" {{"f1": "{letter}{STRING_PAD}"}}
  579. $ kafka-ingest format=avro key-format=avro topic=topic1 schema=${{value-schema}} key-schema=${{key-schema}} repeat={REPEAT}
  580. "${{kafka-ingest.iteration}}"
  581. """
  582. )
  583. for letter in ascii_lowercase[:ITERATIONS]
  584. ]
  585. )
  586. + KafkaScenario.END_MARKER
  587. + dedent(
  588. """
  589. # Expect just the two MARKERs
  590. > SELECT * FROM v1;
  591. 2
  592. > SELECT COUNT(*) FROM s1_tbl;
  593. 2
  594. """
  595. ),
  596. post_restart=KafkaScenario.SCHEMAS + KafkaScenario.POST_RESTART,
  597. materialized_memory="4.5Gb",
  598. clusterd_memory="3.5Gb",
  599. ),
  600. Scenario(
  601. name="table-insert-delete",
  602. pre_restart=dedent(
  603. """
  604. $ postgres-connect name=mz_system url=postgres://mz_system:materialize@${testdrive.materialize-internal-sql-addr}
  605. $ postgres-execute connection=mz_system
  606. ALTER SYSTEM SET max_result_size = 2147483648;
  607. > CREATE TABLE t1 (f1 STRING, f2 STRING)
  608. > CREATE MATERIALIZED VIEW v1 AS SELECT COUNT(*) FROM t1;
  609. """
  610. )
  611. + "\n".join(
  612. [
  613. dedent(
  614. f"""
  615. > INSERT INTO t1 (f1, f2) SELECT '{letter}', REPEAT('a', {PAD_LEN}) || generate_series::text FROM generate_series(1, {REPEAT});
  616. > DELETE FROM t1 WHERE f1 = '{letter}';
  617. """
  618. )
  619. for letter in ascii_lowercase[:ITERATIONS]
  620. ]
  621. )
  622. + dedent(
  623. """
  624. > SELECT * FROM v1;
  625. 0
  626. > SELECT COUNT(*) FROM t1;
  627. 0
  628. """
  629. ),
  630. post_restart=dedent(
  631. """
  632. > SELECT * FROM v1;
  633. 0
  634. > SELECT COUNT(*) FROM t1;
  635. 0
  636. """
  637. ),
  638. materialized_memory="4.5Gb",
  639. clusterd_memory="3.5Gb",
  640. ),
  641. Scenario(
  642. name="table-index-hydration",
  643. pre_restart=dedent(
  644. """
  645. > DROP CLUSTER REPLICA clusterd.r1;
  646. > CREATE TABLE t (a bigint, b bigint);
  647. > CREATE INDEX idx IN CLUSTER clusterd ON t (a);
  648. # We do not want to get a 'canceling statement due to statement timeout' error
  649. > SET statement_timeout = '300s'
  650. # And we do not want the DMLs to be retried in any circumstance
  651. $ set-max-tries max-tries=1
  652. > INSERT INTO t SELECT a, a FROM generate_series(1, 2000000) AS a;
  653. > UPDATE t SET b = b + 100000;
  654. > UPDATE t SET b = b + 1000000;
  655. > UPDATE t SET b = b + 10000000;
  656. > UPDATE t SET b = b + 100000000;
  657. > UPDATE t SET b = b + 1000000000;
  658. > UPDATE t SET a = a + 100000;
  659. > UPDATE t SET a = a + 1000000;
  660. > UPDATE t SET a = a + 10000000;
  661. > UPDATE t SET a = a + 100000000;
  662. > UPDATE t SET a = a + 1000000000;
  663. > CREATE CLUSTER REPLICA clusterd.r1
  664. STORAGECTL ADDRESSES ['clusterd:2100'],
  665. STORAGE ADDRESSES ['clusterd:2103'],
  666. COMPUTECTL ADDRESSES ['clusterd:2101'],
  667. COMPUTE ADDRESSES ['clusterd:2102'];
  668. > SET CLUSTER = clusterd
  669. > SELECT COUNT(*) FROM t;
  670. 2000000
  671. """
  672. ),
  673. post_restart=dedent(
  674. """
  675. > SET CLUSTER = clusterd
  676. > SELECT COUNT(*) FROM t;
  677. 2000000
  678. """
  679. ),
  680. materialized_memory="10Gb",
  681. clusterd_memory="3.5Gb",
  682. ),
  683. Scenario(
  684. name="accumulate-reductions",
  685. pre_restart=dedent(
  686. """
  687. > DROP TABLE IF EXISTS t CASCADE;
  688. > CREATE TABLE t (a int, b int, c int, d int);
  689. > CREATE MATERIALIZED VIEW data AS
  690. SELECT a, a AS b FROM generate_series(1, 10000000) AS a
  691. UNION ALL
  692. SELECT a, b FROM t;
  693. > INSERT INTO t (a, b) VALUES (1, 1);
  694. > INSERT INTO t (a, b) VALUES (0, 0);
  695. > DROP CLUSTER IF EXISTS idx_cluster CASCADE;
  696. > CREATE CLUSTER idx_cluster SIZE '1-8G', REPLICATION FACTOR 2;
  697. > CREATE VIEW accumulable AS
  698. SELECT
  699. a,
  700. sum(a) AS sum_a, COUNT(a) as cnt_a,
  701. sum(b) AS sum_b, COUNT(b) as cnt_b
  702. FROM data
  703. GROUP BY a;
  704. > CREATE INDEX i_accumulable IN CLUSTER idx_cluster ON accumulable(a);
  705. > SET CLUSTER = idx_cluster;
  706. > SELECT COUNT(*) FROM accumulable;
  707. 10000001
  708. """
  709. ),
  710. post_restart=dedent(
  711. """
  712. > SET CLUSTER = idx_cluster;
  713. > SELECT COUNT(*) FROM accumulable;
  714. 10000001
  715. """
  716. ),
  717. materialized_memory="8.5Gb",
  718. clusterd_memory="3.5Gb",
  719. ),
  720. KafkaScenario(
  721. name="upsert-index-hydration",
  722. pre_restart=KafkaScenario.SCHEMAS
  723. + KafkaScenario.CONNECTIONS
  724. + dedent(
  725. f"""
  726. $ kafka-ingest format=avro key-format=avro topic=topic1 schema=${{value-schema}} key-schema=${{key-schema}} repeat={90 * REPEAT}
  727. "${{kafka-ingest.iteration}}" {{"f1": "{STRING_PAD}"}}
  728. """
  729. )
  730. + KafkaScenario.END_MARKER
  731. + dedent(
  732. """
  733. > CREATE SOURCE s1
  734. IN CLUSTER clusterd
  735. FROM KAFKA CONNECTION kafka_conn (TOPIC 'testdrive-topic1-${testdrive.seed}');
  736. > CREATE TABLE s1_tbl FROM SOURCE s1 (REFERENCE "testdrive-topic1-${testdrive.seed}")
  737. FORMAT AVRO USING CONFLUENT SCHEMA REGISTRY CONNECTION csr_conn
  738. ENVELOPE UPSERT;
  739. > DROP CLUSTER REPLICA clusterd.r1;
  740. > CREATE INDEX i1 IN CLUSTER clusterd ON s1_tbl (f1);
  741. """
  742. ),
  743. post_restart=KafkaScenario.SCHEMAS
  744. + dedent(
  745. f"""
  746. > CREATE CLUSTER REPLICA clusterd.r1
  747. STORAGECTL ADDRESSES ['clusterd:2100'],
  748. STORAGE ADDRESSES ['clusterd:2103'],
  749. COMPUTECTL ADDRESSES ['clusterd:2101'],
  750. COMPUTE ADDRESSES ['clusterd:2102'];
  751. > SET CLUSTER = clusterd;
  752. > SELECT COUNT(*) FROM s1_tbl;
  753. {90 * REPEAT + 2}
  754. # Delete all rows except markers
  755. $ kafka-ingest format=avro key-format=avro topic=topic1 schema=${{value-schema}} key-schema=${{key-schema}} repeat={REPEAT}
  756. "${{kafka-ingest.iteration}}"
  757. """
  758. ),
  759. materialized_memory="7.2Gb",
  760. clusterd_memory="3.5Gb",
  761. ),
  762. Scenario(
  763. name="table-aggregate",
  764. pre_restart=dedent(
  765. f"""
  766. > SET statement_timeout = '600 s';
  767. > CREATE TABLE t1 (key1 INTEGER, key2 INTEGER, key3 INTEGER, key4 INTEGER)
  768. > CREATE MATERIALIZED VIEW v1 IN CLUSTER clusterd AS SELECT key1, MIN(key2), MAX(key3) FROM t1 GROUP BY key1;
  769. > CREATE DEFAULT INDEX ON v1;
  770. > CREATE MATERIALIZED VIEW v2 IN CLUSTER clusterd AS SELECT key2, MIN(key1), MAX(key1) FROM t1 GROUP BY key2;
  771. > CREATE DEFAULT INDEX ON v2;
  772. > CREATE MATERIALIZED VIEW v3 IN CLUSTER clusterd AS SELECT key3, MIN(key1), MAX(key1) FROM t1 GROUP BY key3;
  773. > CREATE DEFAULT INDEX ON v3;
  774. > CREATE MATERIALIZED VIEW v4 IN CLUSTER clusterd AS SELECT key4, MIN(key1), MAX(key1) FROM t1 GROUP BY key4;
  775. > CREATE DEFAULT INDEX ON v4;
  776. > INSERT INTO t1 (key1, key2, key3, key4)
  777. SELECT
  778. generate_series,
  779. MOD(generate_series, 10),
  780. MOD(generate_series, 100),
  781. MOD(generate_series, 1000)
  782. FROM generate_series(1, {REPEAT} * {ITERATIONS})
  783. > SELECT COUNT(*) > 0 FROM v1;
  784. true
  785. > SELECT COUNT(*) > 0 FROM v2;
  786. true
  787. > SELECT COUNT(*) > 0 FROM v3;
  788. true
  789. > SELECT COUNT(*) > 0 FROM v4;
  790. true
  791. """
  792. ),
  793. post_restart=dedent(
  794. """
  795. > SELECT COUNT(*) > 0 FROM v1;
  796. true
  797. > SELECT COUNT(*) > 0 FROM v2;
  798. true
  799. > SELECT COUNT(*) > 0 FROM v3;
  800. true
  801. > SELECT COUNT(*) > 0 FROM v4;
  802. true
  803. """
  804. ),
  805. materialized_memory="4.5Gb",
  806. clusterd_memory="5.5Gb",
  807. ),
  808. Scenario(
  809. name="table-outer-join",
  810. pre_restart=dedent(
  811. f"""
  812. > SET statement_timeout = '600 s';
  813. > CREATE TABLE t1 (key1 INTEGER, f1 STRING DEFAULT 'abcdefghi')
  814. > CREATE TABLE t2 (key2 INTEGER, f2 STRING DEFAULT 'abcdefghi')
  815. > CREATE MATERIALIZED VIEW v1
  816. IN CLUSTER clusterd AS
  817. SELECT * FROM t1 LEFT JOIN t2 ON (key1 = key2)
  818. > CREATE DEFAULT INDEX ON v1;
  819. > CREATE MATERIALIZED VIEW v2
  820. IN CLUSTER clusterd AS
  821. SELECT * FROM t2 LEFT JOIN t1 ON (key1 = key2)
  822. > CREATE DEFAULT INDEX ON v2;
  823. > INSERT INTO t1 (key1)
  824. SELECT generate_series FROM generate_series(1, {REPEAT} * {ITERATIONS})
  825. > INSERT INTO t2 (key2)
  826. SELECT MOD(generate_series, 10) FROM generate_series(1, {REPEAT} * {ITERATIONS})
  827. # Records have no match in t2
  828. > INSERT INTO t1 (key1)
  829. SELECT generate_series + 1 * ({REPEAT} * {ITERATIONS})
  830. FROM generate_series(1, {REPEAT} * {ITERATIONS})
  831. # Records have no match in t1
  832. > INSERT INTO t2 (key2)
  833. SELECT generate_series + 2 * ({REPEAT} * {ITERATIONS})
  834. FROM generate_series(1, {REPEAT} * {ITERATIONS})
  835. > SELECT COUNT(*) > 0 FROM v1;
  836. true
  837. > SELECT COUNT(*) > 0 FROM v2;
  838. true
  839. """
  840. ),
  841. post_restart=dedent(
  842. """
  843. > SELECT COUNT(*) > 0 FROM v1;
  844. true
  845. > SELECT COUNT(*) > 0 FROM v2;
  846. true
  847. """
  848. ),
  849. materialized_memory="4.5Gb",
  850. clusterd_memory="3.5Gb",
  851. ),
  852. Scenario(
  853. name="cardinality-estimate-disjunction",
  854. pre_restart=dedent(
  855. """
  856. $ postgres-connect name=mz_system url=postgres://mz_system:materialize@${testdrive.materialize-internal-sql-addr}
  857. $ postgres-execute connection=mz_system
  858. ALTER SYSTEM SET ENABLE_CARDINALITY_ESTIMATES TO TRUE;
  859. > SET ENABLE_SESSION_CARDINALITY_ESTIMATES TO TRUE;
  860. > CREATE TABLE tab0_raw(pk INTEGER, col0 INTEGER, col1 FLOAT, col2 TEXT, col3 INTEGER, col4 FLOAT, col5 TEXT);
  861. > CREATE MATERIALIZED VIEW tab0 AS SELECT DISTINCT ON(pk) * FROM tab0_raw;
  862. > INSERT INTO tab0_raw VALUES(0,6,72.32,'diidw',65,65.1,'uudvn'), (1,57,90.1,'jvnyz',84,48.99,'raktj'), (2,68,91.83,'wefta',37,71.86,'zddoc'), (3,10,78.14,'zwjtc',7,9.96,'epmyn'), (4,63,24.41,'rwaus',66,53.7,'gbgmw'), (5,87,70.88,'rwpww',46,26.5,'bvbew'), (6,76,46.18,'lfvrf',99,92.47,'hqpgb'), (7,25,81.99,'khylz',54,73.22,'qaonp'), (8,93,17.58,'clxlk',88,59.16,'ziwhr'), (9,64,18.54,'fgkop',82,18.73,'lztum');
  863. > CREATE TABLE tab1_raw(pk INTEGER, col0 INTEGER, col1 FLOAT, col2 TEXT, col3 INTEGER, col4 FLOAT, col5 TEXT);
  864. > CREATE MATERIALIZED VIEW tab1 AS SELECT DISTINCT ON(pk) * FROM tab1_raw;
  865. > CREATE INDEX idx_tab1_0 on tab1 (col0);
  866. > CREATE INDEX idx_tab1_1 on tab1 (col1);
  867. > CREATE INDEX idx_tab1_3 on tab1 (col3);
  868. > CREATE INDEX idx_tab1_4 on tab1 (col4);
  869. > INSERT INTO tab1_raw SELECT * FROM tab0;
  870. > CREATE TABLE tab2_raw(pk INTEGER, col0 INTEGER, col1 FLOAT, col2 TEXT, col3 INTEGER, col4 FLOAT, col5 TEXT);
  871. > CREATE MATERIALIZED VIEW tab2 AS SELECT DISTINCT ON(pk) * FROM tab2_raw;
  872. > CREATE INDEX idx_tab2_0 ON tab2 (col4);
  873. > CREATE INDEX idx_tab2_2 ON tab2 (col1);
  874. > CREATE INDEX idx_tab2_4 ON tab2 (col0,col3 DESC);
  875. > CREATE INDEX idx_tab2_5 ON tab2 (col3);
  876. > INSERT INTO tab2_raw SELECT * FROM tab0;
  877. > CREATE TABLE tab3_raw(pk INTEGER, col0 INTEGER, col1 FLOAT, col2 TEXT, col3 INTEGER, col4 FLOAT, col5 TEXT);
  878. > CREATE MATERIALIZED VIEW tab3 AS SELECT DISTINCT ON(pk) * FROM tab3_raw;
  879. > CREATE INDEX idx_tab3_0 ON tab3 (col0,col1,col3);
  880. > CREATE INDEX idx_tab3_1 ON tab3 (col4);
  881. > INSERT INTO tab3_raw SELECT * FROM tab0;
  882. > CREATE TABLE tab4_raw(pk INTEGER, col0 INTEGER, col1 FLOAT, col2 TEXT, col3 INTEGER, col4 FLOAT, col5 TEXT);
  883. > CREATE MATERIALIZED VIEW tab4 AS SELECT DISTINCT ON(pk) * FROM tab4_raw;
  884. > CREATE INDEX idx_tab4_0 ON tab4 (col4 DESC,col3 DESC);
  885. > CREATE INDEX idx_tab4_2 ON tab4 (col1);
  886. > INSERT INTO tab4_raw SELECT * FROM tab0;
  887. > SELECT pk FROM tab0 WHERE col0 <= 88 AND (((col4 <= 97.11 AND col0 IN (11,85,87,63,88) OR (col0 <= 45 AND ((((((((col0 > 79)) OR col1 <= 30.14 OR col3 >= 12))) OR col0 >= 89 OR col1 < 20.99 OR col1 >= 74.51 AND col3 > 77) AND (col0 IN (67,97,94,86,81))) AND ((col1 <= 10.70 AND col1 IS NULL AND col3 > 49 AND col3 > 66 AND (((col4 > 42.2) AND ((((col4 < 86.27) AND col3 >= 77 AND col3 < 48))) AND col3 >= 49)) AND col0 IN (SELECT col3 FROM tab0 WHERE col4 BETWEEN 20.3 AND 97.63))) AND col0 >= 25) OR ((col0 <= 35)) AND col0 < 68 OR ((col0 = 98))) OR (col1 <= 17.96) AND ((((col0 IS NULL))) OR col4 <= 2.63 AND (col0 > 2) AND col3 > 8) OR col3 <= 88 AND (((col0 IS NULL))) OR col0 >= 30)) AND col0 > 5) OR col0 > 3;
  888. 0
  889. 1
  890. 2
  891. 3
  892. 4
  893. 5
  894. 6
  895. 7
  896. 8
  897. 9
  898. ?[version>=14400] EXPLAIN OPTIMIZED PLAN WITH(cardinality) AS VERBOSE TEXT FOR SELECT pk FROM tab0 WHERE col0 <= 88 AND (((col4 <= 97.11 AND col0 IN (11,85,87,63,88) OR (col0 <= 45 AND ((((((((col0 > 79)) OR col1 <= 30.14 OR col3 >= 12))) OR col0 >= 89 OR col1 < 20.99 OR col1 >= 74.51 AND col3 > 77) AND (col0 IN (67,97,94,86,81))) AND ((col1 <= 10.70 AND col1 IS NULL AND col3 > 49 AND col3 > 66 AND (((col4 > 42.2) AND ((((col4 < 86.27) AND col3 >= 77 AND col3 < 48))) AND col3 >= 49)) AND col0 IN (SELECT col3 FROM tab0 WHERE col4 BETWEEN 20.3 AND 97.63))) AND col0 >= 25) OR ((col0 <= 35)) AND col0 < 68 OR ((col0 = 98))) OR (col1 <= 17.96) AND ((((col0 IS NULL))) OR col4 <= 2.63 AND (col0 > 2) AND col3 > 8) OR col3 <= 88 AND (((col0 IS NULL))) OR col0 >= 30)) AND col0 > 5) OR col0 > 3;
  899. Explained Query:
  900. With
  901. cte l0 =
  902. Distinct project=[#0] // { cardinality: \"<UNKNOWN>\" }
  903. Project (#1) // { cardinality: \"<UNKNOWN>\" }
  904. ReadStorage materialize.public.tab0 // { cardinality: \"<UNKNOWN>\" }
  905. cte l1 =
  906. Reduce group_by=[#0] aggregates=[any((#0{col0} = #1{right_col0_0}))] // { cardinality: \"<UNKNOWN>\" }
  907. CrossJoin type=differential // { cardinality: \"<UNKNOWN>\" }
  908. ArrangeBy keys=[[]] // { cardinality: \"<UNKNOWN>\" }
  909. Get l0 // { cardinality: \"<UNKNOWN>\" }
  910. ArrangeBy keys=[[]] // { cardinality: \"<UNKNOWN>\" }
  911. Project (#4) // { cardinality: \"<UNKNOWN>\" }
  912. Filter (#5{col4} <= 97.63) AND (#5{col4} >= 20.3) // { cardinality: \"<UNKNOWN>\" }
  913. ReadStorage materialize.public.tab0 // { cardinality: \"<UNKNOWN>\" }
  914. cte l2 =
  915. Union // { cardinality: \"<UNKNOWN>\" }
  916. Get l1 // { cardinality: \"<UNKNOWN>\" }
  917. Map (false) // { cardinality: \"<UNKNOWN>\" }
  918. Union // { cardinality: \"<UNKNOWN>\" }
  919. Negate // { cardinality: \"<UNKNOWN>\" }
  920. Project (#0) // { cardinality: \"<UNKNOWN>\" }
  921. Get l1 // { cardinality: \"<UNKNOWN>\" }
  922. Get l0 // { cardinality: \"<UNKNOWN>\" }
  923. Return // { cardinality: \"<UNKNOWN>\" }
  924. Project (#0) // { cardinality: \"<UNKNOWN>\" }
  925. Filter ((#1{col0} > 3) OR ((#1{col0} <= 88) AND (#1{col0} > 5) AND ((#1{col0} = 98) OR (#1{col0} >= 30) OR (#6 AND (#2{col1}) IS NULL AND (#3{col3} < 48) AND (#4{col4} < 86.27) AND (#1{col0} <= 45) AND (#2{col1} <= 10.7) AND (#3{col3} > 49) AND (#3{col3} > 66) AND (#4{col4} > 42.2) AND (#1{col0} >= 25) AND (#3{col3} >= 49) AND (#3{col3} >= 77) AND ((#1{col0} = 67) OR (#1{col0} = 81) OR (#1{col0} = 86) OR (#1{col0} = 94) OR (#1{col0} = 97)) AND ((#2{col1} < 20.99) OR (#2{col1} <= 30.14) OR (#1{col0} > 79) OR (#1{col0} >= 89) OR (#3{col3} >= 12) OR ((#3{col3} > 77) AND (#2{col1} >= 74.51)))) OR (#7 AND (#3{col3} <= 88)) OR ((#1{col0} < 68) AND (#1{col0} <= 35)) OR ((#2{col1} <= 17.96) AND (#7 OR ((#4{col4} <= 2.63) AND (#1{col0} > 2) AND (#3{col3} > 8)))) OR ((#4{col4} <= 97.11) AND ((#1{col0} = 11) OR (#1{col0} = 63) OR (#1{col0} = 85) OR (#1{col0} = 87) OR (#1{col0} = 88)))))) // { cardinality: \"<UNKNOWN>\" }
  926. Map ((#1{col0}) IS NULL) // { cardinality: \"<UNKNOWN>\" }
  927. Join on=(#1 = #5) type=differential // { cardinality: \"<UNKNOWN>\" }
  928. ArrangeBy keys=[[#1]] // { cardinality: \"<UNKNOWN>\" }
  929. Project (#0..=#2, #4, #5) // { cardinality: \"<UNKNOWN>\" }
  930. Filter ((#1{col0} > 3) OR ((#1{col0} <= 88) AND (#1{col0} > 5) AND ((#1{col0} = 98) OR (#1{col0} >= 30) OR (#7 AND (#4{col3} <= 88)) OR ((#2{col1}) IS NULL AND (#4{col3} < 48) AND (#5{col4} < 86.27) AND (#1{col0} <= 45) AND (#2{col1} <= 10.7) AND (#4{col3} > 49) AND (#4{col3} > 66) AND (#5{col4} > 42.2) AND (#1{col0} >= 25) AND (#4{col3} >= 49) AND (#4{col3} >= 77) AND ((#1{col0} = 67) OR (#1{col0} = 81) OR (#1{col0} = 86) OR (#1{col0} = 94) OR (#1{col0} = 97)) AND ((#2{col1} < 20.99) OR (#2{col1} <= 30.14) OR (#1{col0} > 79) OR (#1{col0} >= 89) OR (#4{col3} >= 12) OR ((#4{col3} > 77) AND (#2{col1} >= 74.51)))) OR ((#1{col0} < 68) AND (#1{col0} <= 35)) OR ((#2{col1} <= 17.96) AND (#7 OR ((#5{col4} <= 2.63) AND (#1{col0} > 2) AND (#4{col3} > 8)))) OR ((#5{col4} <= 97.11) AND ((#1{col0} = 11) OR (#1{col0} = 63) OR (#1{col0} = 85) OR (#1{col0} = 87) OR (#1{col0} = 88)))))) // { cardinality: \"<UNKNOWN>\" }
  931. Map ((#1{col0}) IS NULL) // { cardinality: \"<UNKNOWN>\" }
  932. ReadStorage materialize.public.tab0 // { cardinality: \"<UNKNOWN>\" }
  933. ArrangeBy keys=[[#0]] // { cardinality: \"<UNKNOWN>\" }
  934. Union // { cardinality: \"<UNKNOWN>\" }
  935. Filter ((#0 > 3) OR ((#0 <= 88) AND (#0 > 5) AND ((#0) IS NULL OR (#0 = 11) OR (#0 = 63) OR (#0 = 85) OR (#0 = 87) OR (#0 = 88) OR (#0 = 98) OR (#0 > 2) OR (#0 >= 30) OR (#1 AND (#0 <= 45) AND (#0 >= 25) AND ((#0 = 67) OR (#0 = 81) OR (#0 = 86) OR (#0 = 94) OR (#0 = 97))) OR ((#0 < 68) AND (#0 <= 35))))) // { cardinality: \"<UNKNOWN>\" }
  936. Get l2 // { cardinality: \"<UNKNOWN>\" }
  937. Project (#0, #18) // { cardinality: \"<UNKNOWN>\" }
  938. Filter (#2 OR (#3 AND #4 AND (#5 OR #6 OR #7 OR #8 OR #9 OR #10 OR #11 OR #12 OR #13 OR #17 OR (#14 AND #15 AND #16)))) AND (#2 OR (#3 AND #4 AND (#5 OR #6 OR #7 OR #8 OR #9 OR #10 OR #11 OR #12 OR #13 OR #17 OR (#14 AND #15 AND #16 AND null)))) // { cardinality: \"<UNKNOWN>\" }
  939. Map ((#0 > 3), (#0 <= 88), (#0 > 5), (#0) IS NULL, (#0 = 11), (#0 = 63), (#0 = 85), (#0 = 87), (#0 = 88), (#0 = 98), (#0 > 2), (#0 >= 30), (#0 <= 45), (#0 >= 25), ((#0 = 67) OR (#0 = 81) OR (#0 = 86) OR (#0 = 94) OR (#0 = 97)), ((#0 < 68) AND (#0 <= 35)), null) // { cardinality: \"<UNKNOWN>\" }
  940. Join on=(#0 = #1) type=differential // { cardinality: \"<UNKNOWN>\" }
  941. ArrangeBy keys=[[#0]] // { cardinality: \"<UNKNOWN>\" }
  942. Union // { cardinality: \"<UNKNOWN>\" }
  943. Negate // { cardinality: \"<UNKNOWN>\" }
  944. Project (#0) // { cardinality: \"<UNKNOWN>\" }
  945. Filter (#2 OR (#3 AND #4 AND (#5 OR #6 OR #7 OR #8 OR #9 OR #10 OR #11 OR #12 OR #13 OR #17 OR (#14 AND #15 AND #16)))) AND (#2 OR (#3 AND #4 AND (#5 OR #6 OR #7 OR #8 OR #9 OR #10 OR #11 OR #12 OR #13 OR #17 OR (#14 AND #15 AND #16 AND null)))) // { cardinality: \"<UNKNOWN>\" }
  946. Map ((#0 > 3), (#0 <= 88), (#0 > 5), (#0) IS NULL, (#0 = 11), (#0 = 63), (#0 = 85), (#0 = 87), (#0 = 88), (#0 = 98), (#0 > 2), (#0 >= 30), (#0 <= 45), (#0 >= 25), ((#0 = 67) OR (#0 = 81) OR (#0 = 86) OR (#0 = 94) OR (#0 = 97)), ((#0 < 68) AND (#0 <= 35))) // { cardinality: \"<UNKNOWN>\" }
  947. Get l2 // { cardinality: \"<UNKNOWN>\" }
  948. Project (#0) // { cardinality: \"<UNKNOWN>\" }
  949. Filter (#1 OR (#2 AND #3 AND (#4 OR #5 OR #6 OR #7 OR #8 OR #9 OR #10 OR #11 OR #12 OR #16 OR (#13 AND #14 AND #15)))) AND (#1 OR (#2 AND #3 AND (#4 OR #5 OR #6 OR #7 OR #8 OR #9 OR #10 OR #11 OR #12 OR #16 OR (#13 AND #14 AND #15 AND null)))) // { cardinality: \"<UNKNOWN>\" }
  950. Map ((#0 > 3), (#0 <= 88), (#0 > 5), (#0) IS NULL, (#0 = 11), (#0 = 63), (#0 = 85), (#0 = 87), (#0 = 88), (#0 = 98), (#0 > 2), (#0 >= 30), (#0 <= 45), (#0 >= 25), ((#0 = 67) OR (#0 = 81) OR (#0 = 86) OR (#0 = 94) OR (#0 = 97)), ((#0 < 68) AND (#0 <= 35))) // { cardinality: \"<UNKNOWN>\" }
  951. Get l0 // { cardinality: \"<UNKNOWN>\" }
  952. ArrangeBy keys=[[#0]] // { cardinality: \"<UNKNOWN>\" }
  953. Get l0 // { cardinality: \"<UNKNOWN>\" }
  954. Source materialize.public.tab0
  955. Target cluster: quickstart
  956. ?[version<14400] EXPLAIN OPTIMIZED PLAN WITH(cardinality) AS VERBOSE TEXT FOR SELECT pk FROM tab0 WHERE col0 <= 88 AND (((col4 <= 97.11 AND col0 IN (11,85,87,63,88) OR (col0 <= 45 AND ((((((((col0 > 79)) OR col1 <= 30.14 OR col3 >= 12))) OR col0 >= 89 OR col1 < 20.99 OR col1 >= 74.51 AND col3 > 77) AND (col0 IN (67,97,94,86,81))) AND ((col1 <= 10.70 AND col1 IS NULL AND col3 > 49 AND col3 > 66 AND (((col4 > 42.2) AND ((((col4 < 86.27) AND col3 >= 77 AND col3 < 48))) AND col3 >= 49)) AND col0 IN (SELECT col3 FROM tab0 WHERE col4 BETWEEN 20.3 AND 97.63))) AND col0 >= 25) OR ((col0 <= 35)) AND col0 < 68 OR ((col0 = 98))) OR (col1 <= 17.96) AND ((((col0 IS NULL))) OR col4 <= 2.63 AND (col0 > 2) AND col3 > 8) OR col3 <= 88 AND (((col0 IS NULL))) OR col0 >= 30)) AND col0 > 5) OR col0 > 3;
  957. Explained Query:
  958. With
  959. cte l0 =
  960. Distinct project=[#0] // { cardinality: "<UNKNOWN>" }
  961. Project (#1) // { cardinality: "<UNKNOWN>" }
  962. ReadStorage materialize.public.tab0 // { cardinality: "<UNKNOWN>" }
  963. cte l1 =
  964. Reduce group_by=[#0] aggregates=[any((#0 = #1))] // { cardinality: "<UNKNOWN>" }
  965. CrossJoin type=differential // { cardinality: "<UNKNOWN>" }
  966. ArrangeBy keys=[[]] // { cardinality: "<UNKNOWN>" }
  967. Get l0 // { cardinality: "<UNKNOWN>" }
  968. ArrangeBy keys=[[]] // { cardinality: "<UNKNOWN>" }
  969. Project (#4) // { cardinality: "<UNKNOWN>" }
  970. Filter (#5 <= 97.63) AND (#5 >= 20.3) // { cardinality: "<UNKNOWN>" }
  971. ReadStorage materialize.public.tab0 // { cardinality: "<UNKNOWN>" }
  972. cte l2 =
  973. Union // { cardinality: "<UNKNOWN>" }
  974. Get l1 // { cardinality: "<UNKNOWN>" }
  975. Map (false) // { cardinality: "<UNKNOWN>" }
  976. Union // { cardinality: "<UNKNOWN>" }
  977. Negate // { cardinality: "<UNKNOWN>" }
  978. Project (#0) // { cardinality: "<UNKNOWN>" }
  979. Get l1 // { cardinality: "<UNKNOWN>" }
  980. Get l0 // { cardinality: "<UNKNOWN>" }
  981. Return // { cardinality: "<UNKNOWN>" }
  982. Project (#0) // { cardinality: "<UNKNOWN>" }
  983. Filter ((#1 > 3) OR ((#1 <= 88) AND (#1 > 5) AND ((#1 = 98) OR (#1 >= 30) OR (#6 AND (#2) IS NULL AND (#3 < 48) AND (#4 < 86.27) AND (#1 <= 45) AND (#2 <= 10.7) AND (#3 > 49) AND (#3 > 66) AND (#4 > 42.2) AND (#1 >= 25) AND (#3 >= 49) AND (#3 >= 77) AND ((#1 = 67) OR (#1 = 81) OR (#1 = 86) OR (#1 = 94) OR (#1 = 97)) AND ((#2 < 20.99) OR (#2 <= 30.14) OR (#1 > 79) OR (#1 >= 89) OR (#3 >= 12) OR ((#3 > 77) AND (#2 >= 74.51)))) OR (#7 AND (#3 <= 88)) OR ((#1 < 68) AND (#1 <= 35)) OR ((#2 <= 17.96) AND (#7 OR ((#4 <= 2.63) AND (#1 > 2) AND (#3 > 8)))) OR ((#4 <= 97.11) AND ((#1 = 11) OR (#1 = 63) OR (#1 = 85) OR (#1 = 87) OR (#1 = 88)))))) // { cardinality: "<UNKNOWN>" }
  984. Map ((#1) IS NULL) // { cardinality: "<UNKNOWN>" }
  985. Join on=(#1 = #5) type=differential // { cardinality: "<UNKNOWN>" }
  986. ArrangeBy keys=[[#1]] // { cardinality: "<UNKNOWN>" }
  987. Project (#0..=#2, #4, #5) // { cardinality: "<UNKNOWN>" }
  988. Filter ((#1 > 3) OR ((#1 <= 88) AND (#1 > 5) AND ((#1 = 98) OR (#1 >= 30) OR (#7 AND (#4 <= 88)) OR ((#2) IS NULL AND (#4 < 48) AND (#5 < 86.27) AND (#1 <= 45) AND (#2 <= 10.7) AND (#4 > 49) AND (#4 > 66) AND (#5 > 42.2) AND (#1 >= 25) AND (#4 >= 49) AND (#4 >= 77) AND ((#1 = 67) OR (#1 = 81) OR (#1 = 86) OR (#1 = 94) OR (#1 = 97)) AND ((#2 < 20.99) OR (#2 <= 30.14) OR (#1 > 79) OR (#1 >= 89) OR (#4 >= 12) OR ((#4 > 77) AND (#2 >= 74.51)))) OR ((#1 < 68) AND (#1 <= 35)) OR ((#2 <= 17.96) AND (#7 OR ((#5 <= 2.63) AND (#1 > 2) AND (#4 > 8)))) OR ((#5 <= 97.11) AND ((#1 = 11) OR (#1 = 63) OR (#1 = 85) OR (#1 = 87) OR (#1 = 88)))))) // { cardinality: "<UNKNOWN>" }
  989. Map ((#1) IS NULL) // { cardinality: "<UNKNOWN>" }
  990. ReadStorage materialize.public.tab0 // { cardinality: "<UNKNOWN>" }
  991. ArrangeBy keys=[[#0]] // { cardinality: "<UNKNOWN>" }
  992. Union // { cardinality: "<UNKNOWN>" }
  993. Filter ((#0 > 3) OR ((#0 <= 88) AND (#0 > 5) AND ((#0) IS NULL OR (#0 = 11) OR (#0 = 63) OR (#0 = 85) OR (#0 = 87) OR (#0 = 88) OR (#0 = 98) OR (#0 > 2) OR (#0 >= 30) OR (#1 AND (#0 <= 45) AND (#0 >= 25) AND ((#0 = 67) OR (#0 = 81) OR (#0 = 86) OR (#0 = 94) OR (#0 = 97))) OR ((#0 < 68) AND (#0 <= 35))))) // { cardinality: "<UNKNOWN>" }
  994. Get l2 // { cardinality: "<UNKNOWN>" }
  995. Project (#0, #18) // { cardinality: "<UNKNOWN>" }
  996. Filter (#2 OR (#3 AND #4 AND (#5 OR #6 OR #7 OR #8 OR #9 OR #10 OR #11 OR #12 OR #13 OR #17 OR (#14 AND #15 AND #16)))) AND (#2 OR (#3 AND #4 AND (#5 OR #6 OR #7 OR #8 OR #9 OR #10 OR #11 OR #12 OR #13 OR #17 OR (#14 AND #15 AND #16 AND null)))) // { cardinality: "<UNKNOWN>" }
  997. Map ((#0 > 3), (#0 <= 88), (#0 > 5), (#0) IS NULL, (#0 = 11), (#0 = 63), (#0 = 85), (#0 = 87), (#0 = 88), (#0 = 98), (#0 > 2), (#0 >= 30), (#0 <= 45), (#0 >= 25), ((#0 = 67) OR (#0 = 81) OR (#0 = 86) OR (#0 = 94) OR (#0 = 97)), ((#0 < 68) AND (#0 <= 35)), null) // { cardinality: "<UNKNOWN>" }
  998. Join on=(#0 = #1) type=differential // { cardinality: "<UNKNOWN>" }
  999. ArrangeBy keys=[[#0]] // { cardinality: "<UNKNOWN>" }
  1000. Union // { cardinality: "<UNKNOWN>" }
  1001. Negate // { cardinality: "<UNKNOWN>" }
  1002. Project (#0) // { cardinality: "<UNKNOWN>" }
  1003. Filter (#2 OR (#3 AND #4 AND (#5 OR #6 OR #7 OR #8 OR #9 OR #10 OR #11 OR #12 OR #13 OR #17 OR (#14 AND #15 AND #16)))) AND (#2 OR (#3 AND #4 AND (#5 OR #6 OR #7 OR #8 OR #9 OR #10 OR #11 OR #12 OR #13 OR #17 OR (#14 AND #15 AND #16 AND null)))) // { cardinality: "<UNKNOWN>" }
  1004. Map ((#0 > 3), (#0 <= 88), (#0 > 5), (#0) IS NULL, (#0 = 11), (#0 = 63), (#0 = 85), (#0 = 87), (#0 = 88), (#0 = 98), (#0 > 2), (#0 >= 30), (#0 <= 45), (#0 >= 25), ((#0 = 67) OR (#0 = 81) OR (#0 = 86) OR (#0 = 94) OR (#0 = 97)), ((#0 < 68) AND (#0 <= 35))) // { cardinality: "<UNKNOWN>" }
  1005. Get l2 // { cardinality: "<UNKNOWN>" }
  1006. Project (#0) // { cardinality: "<UNKNOWN>" }
  1007. Filter (#1 OR (#2 AND #3 AND (#4 OR #5 OR #6 OR #7 OR #8 OR #9 OR #10 OR #11 OR #12 OR #16 OR (#13 AND #14 AND #15)))) AND (#1 OR (#2 AND #3 AND (#4 OR #5 OR #6 OR #7 OR #8 OR #9 OR #10 OR #11 OR #12 OR #16 OR (#13 AND #14 AND #15 AND null)))) // { cardinality: "<UNKNOWN>" }
  1008. Map ((#0 > 3), (#0 <= 88), (#0 > 5), (#0) IS NULL, (#0 = 11), (#0 = 63), (#0 = 85), (#0 = 87), (#0 = 88), (#0 = 98), (#0 > 2), (#0 >= 30), (#0 <= 45), (#0 >= 25), ((#0 = 67) OR (#0 = 81) OR (#0 = 86) OR (#0 = 94) OR (#0 = 97)), ((#0 < 68) AND (#0 <= 35))) // { cardinality: "<UNKNOWN>" }
  1009. Get l0 // { cardinality: "<UNKNOWN>" }
  1010. ArrangeBy keys=[[#0]] // { cardinality: "<UNKNOWN>" }
  1011. Get l0 // { cardinality: "<UNKNOWN>" }
  1012. Source materialize.public.tab0
  1013. Target cluster: quickstart
  1014. """
  1015. ),
  1016. post_restart=dedent(
  1017. """
  1018. > SELECT pk FROM tab0 WHERE col0 <= 88 AND (((col4 <= 97.11 AND col0 IN (11,85,87,63,88) OR (col0 <= 45 AND ((((((((col0 > 79)) OR col1 <= 30.14 OR col3 >= 12))) OR col0 >= 89 OR col1 < 20.99 OR col1 >= 74.51 AND col3 > 77) AND (col0 IN (67,97,94,86,81))) AND ((col1 <= 10.70 AND col1 IS NULL AND col3 > 49 AND col3 > 66 AND (((col4 > 42.2) AND ((((col4 < 86.27) AND col3 >= 77 AND col3 < 48))) AND col3 >= 49)) AND col0 IN (SELECT col3 FROM tab0 WHERE col4 BETWEEN 20.3 AND 97.63))) AND col0 >= 25) OR ((col0 <= 35)) AND col0 < 68 OR ((col0 = 98))) OR (col1 <= 17.96) AND ((((col0 IS NULL))) OR col4 <= 2.63 AND (col0 > 2) AND col3 > 8) OR col3 <= 88 AND (((col0 IS NULL))) OR col0 >= 30)) AND col0 > 5) OR col0 > 3;
  1019. 0
  1020. 1
  1021. 2
  1022. 3
  1023. 4
  1024. 5
  1025. 6
  1026. 7
  1027. 8
  1028. 9
  1029. ?[version>=14400] EXPLAIN OPTIMIZED PLAN WITH(cardinality) AS VERBOSE TEXT FOR SELECT pk FROM tab0 WHERE col0 <= 88 AND (((col4 <= 97.11 AND col0 IN (11,85,87,63,88) OR (col0 <= 45 AND ((((((((col0 > 79)) OR col1 <= 30.14 OR col3 >= 12))) OR col0 >= 89 OR col1 < 20.99 OR col1 >= 74.51 AND col3 > 77) AND (col0 IN (67,97,94,86,81))) AND ((col1 <= 10.70 AND col1 IS NULL AND col3 > 49 AND col3 > 66 AND (((col4 > 42.2) AND ((((col4 < 86.27) AND col3 >= 77 AND col3 < 48))) AND col3 >= 49)) AND col0 IN (SELECT col3 FROM tab0 WHERE col4 BETWEEN 20.3 AND 97.63))) AND col0 >= 25) OR ((col0 <= 35)) AND col0 < 68 OR ((col0 = 98))) OR (col1 <= 17.96) AND ((((col0 IS NULL))) OR col4 <= 2.63 AND (col0 > 2) AND col3 > 8) OR col3 <= 88 AND (((col0 IS NULL))) OR col0 >= 30)) AND col0 > 5) OR col0 > 3;
  1030. Explained Query:
  1031. With
  1032. cte l0 =
  1033. Distinct project=[#0] // { cardinality: \"<UNKNOWN>\" }
  1034. Project (#1) // { cardinality: \"<UNKNOWN>\" }
  1035. ReadStorage materialize.public.tab0 // { cardinality: \"<UNKNOWN>\" }
  1036. cte l1 =
  1037. Reduce group_by=[#0] aggregates=[any((#0{col0} = #1{right_col0_0}))] // { cardinality: \"<UNKNOWN>\" }
  1038. CrossJoin type=differential // { cardinality: \"<UNKNOWN>\" }
  1039. ArrangeBy keys=[[]] // { cardinality: \"<UNKNOWN>\" }
  1040. Get l0 // { cardinality: \"<UNKNOWN>\" }
  1041. ArrangeBy keys=[[]] // { cardinality: \"<UNKNOWN>\" }
  1042. Project (#4) // { cardinality: \"<UNKNOWN>\" }
  1043. Filter (#5{col4} <= 97.63) AND (#5{col4} >= 20.3) // { cardinality: \"<UNKNOWN>\" }
  1044. ReadStorage materialize.public.tab0 // { cardinality: \"<UNKNOWN>\" }
  1045. cte l2 =
  1046. Union // { cardinality: \"<UNKNOWN>\" }
  1047. Get l1 // { cardinality: \"<UNKNOWN>\" }
  1048. Map (false) // { cardinality: \"<UNKNOWN>\" }
  1049. Union // { cardinality: \"<UNKNOWN>\" }
  1050. Negate // { cardinality: \"<UNKNOWN>\" }
  1051. Project (#0) // { cardinality: \"<UNKNOWN>\" }
  1052. Get l1 // { cardinality: \"<UNKNOWN>\" }
  1053. Get l0 // { cardinality: \"<UNKNOWN>\" }
  1054. Return // { cardinality: \"<UNKNOWN>\" }
  1055. Project (#0) // { cardinality: \"<UNKNOWN>\" }
  1056. Filter ((#1{col0} > 3) OR ((#1{col0} <= 88) AND (#1{col0} > 5) AND ((#1{col0} = 98) OR (#1{col0} >= 30) OR (#6 AND (#2{col1}) IS NULL AND (#3{col3} < 48) AND (#4{col4} < 86.27) AND (#1{col0} <= 45) AND (#2{col1} <= 10.7) AND (#3{col3} > 49) AND (#3{col3} > 66) AND (#4{col4} > 42.2) AND (#1{col0} >= 25) AND (#3{col3} >= 49) AND (#3{col3} >= 77) AND ((#1{col0} = 67) OR (#1{col0} = 81) OR (#1{col0} = 86) OR (#1{col0} = 94) OR (#1{col0} = 97)) AND ((#2{col1} < 20.99) OR (#2{col1} <= 30.14) OR (#1{col0} > 79) OR (#1{col0} >= 89) OR (#3{col3} >= 12) OR ((#3{col3} > 77) AND (#2{col1} >= 74.51)))) OR (#7 AND (#3{col3} <= 88)) OR ((#1{col0} < 68) AND (#1{col0} <= 35)) OR ((#2{col1} <= 17.96) AND (#7 OR ((#4{col4} <= 2.63) AND (#1{col0} > 2) AND (#3{col3} > 8)))) OR ((#4{col4} <= 97.11) AND ((#1{col0} = 11) OR (#1{col0} = 63) OR (#1{col0} = 85) OR (#1{col0} = 87) OR (#1{col0} = 88)))))) // { cardinality: \"<UNKNOWN>\" }
  1057. Map ((#1{col0}) IS NULL) // { cardinality: \"<UNKNOWN>\" }
  1058. Join on=(#1 = #5) type=differential // { cardinality: \"<UNKNOWN>\" }
  1059. ArrangeBy keys=[[#1]] // { cardinality: \"<UNKNOWN>\" }
  1060. Project (#0..=#2, #4, #5) // { cardinality: \"<UNKNOWN>\" }
  1061. Filter ((#1{col0} > 3) OR ((#1{col0} <= 88) AND (#1{col0} > 5) AND ((#1{col0} = 98) OR (#1{col0} >= 30) OR (#7 AND (#4{col3} <= 88)) OR ((#2{col1}) IS NULL AND (#4{col3} < 48) AND (#5{col4} < 86.27) AND (#1{col0} <= 45) AND (#2{col1} <= 10.7) AND (#4{col3} > 49) AND (#4{col3} > 66) AND (#5{col4} > 42.2) AND (#1{col0} >= 25) AND (#4{col3} >= 49) AND (#4{col3} >= 77) AND ((#1{col0} = 67) OR (#1{col0} = 81) OR (#1{col0} = 86) OR (#1{col0} = 94) OR (#1{col0} = 97)) AND ((#2{col1} < 20.99) OR (#2{col1} <= 30.14) OR (#1{col0} > 79) OR (#1{col0} >= 89) OR (#4{col3} >= 12) OR ((#4{col3} > 77) AND (#2{col1} >= 74.51)))) OR ((#1{col0} < 68) AND (#1{col0} <= 35)) OR ((#2{col1} <= 17.96) AND (#7 OR ((#5{col4} <= 2.63) AND (#1{col0} > 2) AND (#4{col3} > 8)))) OR ((#5{col4} <= 97.11) AND ((#1{col0} = 11) OR (#1{col0} = 63) OR (#1{col0} = 85) OR (#1{col0} = 87) OR (#1{col0} = 88)))))) // { cardinality: \"<UNKNOWN>\" }
  1062. Map ((#1{col0}) IS NULL) // { cardinality: \"<UNKNOWN>\" }
  1063. ReadStorage materialize.public.tab0 // { cardinality: \"<UNKNOWN>\" }
  1064. ArrangeBy keys=[[#0]] // { cardinality: \"<UNKNOWN>\" }
  1065. Union // { cardinality: \"<UNKNOWN>\" }
  1066. Filter ((#0 > 3) OR ((#0 <= 88) AND (#0 > 5) AND ((#0) IS NULL OR (#0 = 11) OR (#0 = 63) OR (#0 = 85) OR (#0 = 87) OR (#0 = 88) OR (#0 = 98) OR (#0 > 2) OR (#0 >= 30) OR (#1 AND (#0 <= 45) AND (#0 >= 25) AND ((#0 = 67) OR (#0 = 81) OR (#0 = 86) OR (#0 = 94) OR (#0 = 97))) OR ((#0 < 68) AND (#0 <= 35))))) // { cardinality: \"<UNKNOWN>\" }
  1067. Get l2 // { cardinality: \"<UNKNOWN>\" }
  1068. Project (#0, #18) // { cardinality: \"<UNKNOWN>\" }
  1069. Filter (#2 OR (#3 AND #4 AND (#5 OR #6 OR #7 OR #8 OR #9 OR #10 OR #11 OR #12 OR #13 OR #17 OR (#14 AND #15 AND #16)))) AND (#2 OR (#3 AND #4 AND (#5 OR #6 OR #7 OR #8 OR #9 OR #10 OR #11 OR #12 OR #13 OR #17 OR (#14 AND #15 AND #16 AND null)))) // { cardinality: \"<UNKNOWN>\" }
  1070. Map ((#0 > 3), (#0 <= 88), (#0 > 5), (#0) IS NULL, (#0 = 11), (#0 = 63), (#0 = 85), (#0 = 87), (#0 = 88), (#0 = 98), (#0 > 2), (#0 >= 30), (#0 <= 45), (#0 >= 25), ((#0 = 67) OR (#0 = 81) OR (#0 = 86) OR (#0 = 94) OR (#0 = 97)), ((#0 < 68) AND (#0 <= 35)), null) // { cardinality: \"<UNKNOWN>\" }
  1071. Join on=(#0 = #1) type=differential // { cardinality: \"<UNKNOWN>\" }
  1072. ArrangeBy keys=[[#0]] // { cardinality: \"<UNKNOWN>\" }
  1073. Union // { cardinality: \"<UNKNOWN>\" }
  1074. Negate // { cardinality: \"<UNKNOWN>\" }
  1075. Project (#0) // { cardinality: \"<UNKNOWN>\" }
  1076. Filter (#2 OR (#3 AND #4 AND (#5 OR #6 OR #7 OR #8 OR #9 OR #10 OR #11 OR #12 OR #13 OR #17 OR (#14 AND #15 AND #16)))) AND (#2 OR (#3 AND #4 AND (#5 OR #6 OR #7 OR #8 OR #9 OR #10 OR #11 OR #12 OR #13 OR #17 OR (#14 AND #15 AND #16 AND null)))) // { cardinality: \"<UNKNOWN>\" }
  1077. Map ((#0 > 3), (#0 <= 88), (#0 > 5), (#0) IS NULL, (#0 = 11), (#0 = 63), (#0 = 85), (#0 = 87), (#0 = 88), (#0 = 98), (#0 > 2), (#0 >= 30), (#0 <= 45), (#0 >= 25), ((#0 = 67) OR (#0 = 81) OR (#0 = 86) OR (#0 = 94) OR (#0 = 97)), ((#0 < 68) AND (#0 <= 35))) // { cardinality: \"<UNKNOWN>\" }
  1078. Get l2 // { cardinality: \"<UNKNOWN>\" }
  1079. Project (#0) // { cardinality: \"<UNKNOWN>\" }
  1080. Filter (#1 OR (#2 AND #3 AND (#4 OR #5 OR #6 OR #7 OR #8 OR #9 OR #10 OR #11 OR #12 OR #16 OR (#13 AND #14 AND #15)))) AND (#1 OR (#2 AND #3 AND (#4 OR #5 OR #6 OR #7 OR #8 OR #9 OR #10 OR #11 OR #12 OR #16 OR (#13 AND #14 AND #15 AND null)))) // { cardinality: \"<UNKNOWN>\" }
  1081. Map ((#0 > 3), (#0 <= 88), (#0 > 5), (#0) IS NULL, (#0 = 11), (#0 = 63), (#0 = 85), (#0 = 87), (#0 = 88), (#0 = 98), (#0 > 2), (#0 >= 30), (#0 <= 45), (#0 >= 25), ((#0 = 67) OR (#0 = 81) OR (#0 = 86) OR (#0 = 94) OR (#0 = 97)), ((#0 < 68) AND (#0 <= 35))) // { cardinality: \"<UNKNOWN>\" }
  1082. Get l0 // { cardinality: \"<UNKNOWN>\" }
  1083. ArrangeBy keys=[[#0]] // { cardinality: \"<UNKNOWN>\" }
  1084. Get l0 // { cardinality: \"<UNKNOWN>\" }
  1085. Source materialize.public.tab0
  1086. Target cluster: quickstart
  1087. ?[version<14400] EXPLAIN OPTIMIZED PLAN WITH(cardinality) AS VERBOSE TEXT FOR SELECT pk FROM tab0 WHERE col0 <= 88 AND (((col4 <= 97.11 AND col0 IN (11,85,87,63,88) OR (col0 <= 45 AND ((((((((col0 > 79)) OR col1 <= 30.14 OR col3 >= 12))) OR col0 >= 89 OR col1 < 20.99 OR col1 >= 74.51 AND col3 > 77) AND (col0 IN (67,97,94,86,81))) AND ((col1 <= 10.70 AND col1 IS NULL AND col3 > 49 AND col3 > 66 AND (((col4 > 42.2) AND ((((col4 < 86.27) AND col3 >= 77 AND col3 < 48))) AND col3 >= 49)) AND col0 IN (SELECT col3 FROM tab0 WHERE col4 BETWEEN 20.3 AND 97.63))) AND col0 >= 25) OR ((col0 <= 35)) AND col0 < 68 OR ((col0 = 98))) OR (col1 <= 17.96) AND ((((col0 IS NULL))) OR col4 <= 2.63 AND (col0 > 2) AND col3 > 8) OR col3 <= 88 AND (((col0 IS NULL))) OR col0 >= 30)) AND col0 > 5) OR col0 > 3;
  1088. Explained Query:
  1089. With
  1090. cte l0 =
  1091. Distinct project=[#0] // { cardinality: "<UNKNOWN>" }
  1092. Project (#1) // { cardinality: "<UNKNOWN>" }
  1093. ReadStorage materialize.public.tab0 // { cardinality: "<UNKNOWN>" }
  1094. cte l1 =
  1095. Reduce group_by=[#0] aggregates=[any((#0 = #1))] // { cardinality: "<UNKNOWN>" }
  1096. CrossJoin type=differential // { cardinality: "<UNKNOWN>" }
  1097. ArrangeBy keys=[[]] // { cardinality: "<UNKNOWN>" }
  1098. Get l0 // { cardinality: "<UNKNOWN>" }
  1099. ArrangeBy keys=[[]] // { cardinality: "<UNKNOWN>" }
  1100. Project (#4) // { cardinality: "<UNKNOWN>" }
  1101. Filter (#5 <= 97.63) AND (#5 >= 20.3) // { cardinality: "<UNKNOWN>" }
  1102. ReadStorage materialize.public.tab0 // { cardinality: "<UNKNOWN>" }
  1103. cte l2 =
  1104. Union // { cardinality: "<UNKNOWN>" }
  1105. Get l1 // { cardinality: "<UNKNOWN>" }
  1106. Map (false) // { cardinality: "<UNKNOWN>" }
  1107. Union // { cardinality: "<UNKNOWN>" }
  1108. Negate // { cardinality: "<UNKNOWN>" }
  1109. Project (#0) // { cardinality: "<UNKNOWN>" }
  1110. Get l1 // { cardinality: "<UNKNOWN>" }
  1111. Get l0 // { cardinality: "<UNKNOWN>" }
  1112. Return // { cardinality: "<UNKNOWN>" }
  1113. Project (#0) // { cardinality: "<UNKNOWN>" }
  1114. Filter ((#1 > 3) OR ((#1 <= 88) AND (#1 > 5) AND ((#1 = 98) OR (#1 >= 30) OR (#6 AND (#2) IS NULL AND (#3 < 48) AND (#4 < 86.27) AND (#1 <= 45) AND (#2 <= 10.7) AND (#3 > 49) AND (#3 > 66) AND (#4 > 42.2) AND (#1 >= 25) AND (#3 >= 49) AND (#3 >= 77) AND ((#1 = 67) OR (#1 = 81) OR (#1 = 86) OR (#1 = 94) OR (#1 = 97)) AND ((#2 < 20.99) OR (#2 <= 30.14) OR (#1 > 79) OR (#1 >= 89) OR (#3 >= 12) OR ((#3 > 77) AND (#2 >= 74.51)))) OR (#7 AND (#3 <= 88)) OR ((#1 < 68) AND (#1 <= 35)) OR ((#2 <= 17.96) AND (#7 OR ((#4 <= 2.63) AND (#1 > 2) AND (#3 > 8)))) OR ((#4 <= 97.11) AND ((#1 = 11) OR (#1 = 63) OR (#1 = 85) OR (#1 = 87) OR (#1 = 88)))))) // { cardinality: "<UNKNOWN>" }
  1115. Map ((#1) IS NULL) // { cardinality: "<UNKNOWN>" }
  1116. Join on=(#1 = #5) type=differential // { cardinality: "<UNKNOWN>" }
  1117. ArrangeBy keys=[[#1]] // { cardinality: "<UNKNOWN>" }
  1118. Project (#0..=#2, #4, #5) // { cardinality: "<UNKNOWN>" }
  1119. Filter ((#1 > 3) OR ((#1 <= 88) AND (#1 > 5) AND ((#1 = 98) OR (#1 >= 30) OR (#7 AND (#4 <= 88)) OR ((#2) IS NULL AND (#4 < 48) AND (#5 < 86.27) AND (#1 <= 45) AND (#2 <= 10.7) AND (#4 > 49) AND (#4 > 66) AND (#5 > 42.2) AND (#1 >= 25) AND (#4 >= 49) AND (#4 >= 77) AND ((#1 = 67) OR (#1 = 81) OR (#1 = 86) OR (#1 = 94) OR (#1 = 97)) AND ((#2 < 20.99) OR (#2 <= 30.14) OR (#1 > 79) OR (#1 >= 89) OR (#4 >= 12) OR ((#4 > 77) AND (#2 >= 74.51)))) OR ((#1 < 68) AND (#1 <= 35)) OR ((#2 <= 17.96) AND (#7 OR ((#5 <= 2.63) AND (#1 > 2) AND (#4 > 8)))) OR ((#5 <= 97.11) AND ((#1 = 11) OR (#1 = 63) OR (#1 = 85) OR (#1 = 87) OR (#1 = 88)))))) // { cardinality: "<UNKNOWN>" }
  1120. Map ((#1) IS NULL) // { cardinality: "<UNKNOWN>" }
  1121. ReadStorage materialize.public.tab0 // { cardinality: "<UNKNOWN>" }
  1122. ArrangeBy keys=[[#0]] // { cardinality: "<UNKNOWN>" }
  1123. Union // { cardinality: "<UNKNOWN>" }
  1124. Filter ((#0 > 3) OR ((#0 <= 88) AND (#0 > 5) AND ((#0) IS NULL OR (#0 = 11) OR (#0 = 63) OR (#0 = 85) OR (#0 = 87) OR (#0 = 88) OR (#0 = 98) OR (#0 > 2) OR (#0 >= 30) OR (#1 AND (#0 <= 45) AND (#0 >= 25) AND ((#0 = 67) OR (#0 = 81) OR (#0 = 86) OR (#0 = 94) OR (#0 = 97))) OR ((#0 < 68) AND (#0 <= 35))))) // { cardinality: "<UNKNOWN>" }
  1125. Get l2 // { cardinality: "<UNKNOWN>" }
  1126. Project (#0, #18) // { cardinality: "<UNKNOWN>" }
  1127. Filter (#2 OR (#3 AND #4 AND (#5 OR #6 OR #7 OR #8 OR #9 OR #10 OR #11 OR #12 OR #13 OR #17 OR (#14 AND #15 AND #16)))) AND (#2 OR (#3 AND #4 AND (#5 OR #6 OR #7 OR #8 OR #9 OR #10 OR #11 OR #12 OR #13 OR #17 OR (#14 AND #15 AND #16 AND null)))) // { cardinality: "<UNKNOWN>" }
  1128. Map ((#0 > 3), (#0 <= 88), (#0 > 5), (#0) IS NULL, (#0 = 11), (#0 = 63), (#0 = 85), (#0 = 87), (#0 = 88), (#0 = 98), (#0 > 2), (#0 >= 30), (#0 <= 45), (#0 >= 25), ((#0 = 67) OR (#0 = 81) OR (#0 = 86) OR (#0 = 94) OR (#0 = 97)), ((#0 < 68) AND (#0 <= 35)), null) // { cardinality: "<UNKNOWN>" }
  1129. Join on=(#0 = #1) type=differential // { cardinality: "<UNKNOWN>" }
  1130. ArrangeBy keys=[[#0]] // { cardinality: "<UNKNOWN>" }
  1131. Union // { cardinality: "<UNKNOWN>" }
  1132. Negate // { cardinality: "<UNKNOWN>" }
  1133. Project (#0) // { cardinality: "<UNKNOWN>" }
  1134. Filter (#2 OR (#3 AND #4 AND (#5 OR #6 OR #7 OR #8 OR #9 OR #10 OR #11 OR #12 OR #13 OR #17 OR (#14 AND #15 AND #16)))) AND (#2 OR (#3 AND #4 AND (#5 OR #6 OR #7 OR #8 OR #9 OR #10 OR #11 OR #12 OR #13 OR #17 OR (#14 AND #15 AND #16 AND null)))) // { cardinality: "<UNKNOWN>" }
  1135. Map ((#0 > 3), (#0 <= 88), (#0 > 5), (#0) IS NULL, (#0 = 11), (#0 = 63), (#0 = 85), (#0 = 87), (#0 = 88), (#0 = 98), (#0 > 2), (#0 >= 30), (#0 <= 45), (#0 >= 25), ((#0 = 67) OR (#0 = 81) OR (#0 = 86) OR (#0 = 94) OR (#0 = 97)), ((#0 < 68) AND (#0 <= 35))) // { cardinality: "<UNKNOWN>" }
  1136. Get l2 // { cardinality: "<UNKNOWN>" }
  1137. Project (#0) // { cardinality: "<UNKNOWN>" }
  1138. Filter (#1 OR (#2 AND #3 AND (#4 OR #5 OR #6 OR #7 OR #8 OR #9 OR #10 OR #11 OR #12 OR #16 OR (#13 AND #14 AND #15)))) AND (#1 OR (#2 AND #3 AND (#4 OR #5 OR #6 OR #7 OR #8 OR #9 OR #10 OR #11 OR #12 OR #16 OR (#13 AND #14 AND #15 AND null)))) // { cardinality: "<UNKNOWN>" }
  1139. Map ((#0 > 3), (#0 <= 88), (#0 > 5), (#0) IS NULL, (#0 = 11), (#0 = 63), (#0 = 85), (#0 = 87), (#0 = 88), (#0 = 98), (#0 > 2), (#0 >= 30), (#0 <= 45), (#0 >= 25), ((#0 = 67) OR (#0 = 81) OR (#0 = 86) OR (#0 = 94) OR (#0 = 97)), ((#0 < 68) AND (#0 <= 35))) // { cardinality: "<UNKNOWN>" }
  1140. Get l0 // { cardinality: "<UNKNOWN>" }
  1141. ArrangeBy keys=[[#0]] // { cardinality: "<UNKNOWN>" }
  1142. Get l0 // { cardinality: "<UNKNOWN>" }
  1143. Source materialize.public.tab0
  1144. Target cluster: quickstart
  1145. """
  1146. ),
  1147. materialized_memory="4.5Gb",
  1148. clusterd_memory="3.5Gb",
  1149. ),
  1150. Scenario(
  1151. name="dataflow-logical-backpressure",
  1152. pre_restart=dedent(
  1153. """
  1154. # * Timestamp interval to quickly create a source with many distinct timestamps.
  1155. # * Lgalloc disabled to force more memory pressure.
  1156. # * Index options to enable retained history.
  1157. # * Finally, enable backpressure.
  1158. $ postgres-connect name=mz_system url=postgres://mz_system:materialize@${testdrive.materialize-internal-sql-addr}
  1159. $ postgres-execute connection=mz_system
  1160. ALTER SYSTEM SET min_timestamp_interval = '10ms';
  1161. ALTER SYSTEM SET enable_lgalloc = false;
  1162. ALTER SYSTEM SET enable_index_options = true;
  1163. ALTER SYSTEM SET enable_compute_logical_backpressure = true;
  1164. > DROP CLUSTER REPLICA clusterd.r1;
  1165. # Table to hold back frontiers.
  1166. > CREATE TABLE t (a int);
  1167. > INSERT INTO t VALUES (1);
  1168. # Create a source with 512 distinct timestamps.
  1169. > CREATE SOURCE counter FROM LOAD GENERATOR COUNTER (TICK INTERVAL '100ms', UP TO 512) WITH (TIMESTAMP INTERVAL '100ms', RETAIN HISTORY FOR '10d');
  1170. > CREATE MATERIALIZED VIEW cv WITH (RETAIN HISTORY FOR '10d') AS SELECT counter FROM counter, t;
  1171. # Wait until counter is fully ingested.
  1172. > SELECT COUNT(*) FROM counter;
  1173. 512
  1174. > CREATE CLUSTER REPLICA clusterd.r1
  1175. STORAGECTL ADDRESSES ['clusterd:2100'],
  1176. STORAGE ADDRESSES ['clusterd:2103'],
  1177. COMPUTECTL ADDRESSES ['clusterd:2101'],
  1178. COMPUTE ADDRESSES ['clusterd:2102'];
  1179. > SET CLUSTER = clusterd
  1180. # Ballast is the concatenation of two 32-byte strings, for readability.
  1181. > CREATE VIEW v AS
  1182. SELECT
  1183. c1.counter + c2.counter * 10 + c3.counter * 100 AS c,
  1184. '01234567890123456789012345678901'||'01234567890123456789012345678901' AS ballast
  1185. FROM
  1186. cv c1,
  1187. cv c2,
  1188. cv c3;
  1189. > CREATE DEFAULT INDEX ON v WITH (RETAIN HISTORY FOR '10d');
  1190. > SELECT COUNT(*) > 0 FROM v;
  1191. true
  1192. """
  1193. ),
  1194. post_restart=dedent(
  1195. """
  1196. > SET CLUSTER = clusterd
  1197. > SELECT COUNT(*) > 0 FROM v;
  1198. true
  1199. """
  1200. ),
  1201. materialized_memory="10Gb",
  1202. clusterd_memory="3.5Gb",
  1203. ),
  1204. ]
  1205. def workflow_default(c: Composition, parser: WorkflowArgumentParser) -> None:
  1206. def process(name: str) -> None:
  1207. if name in ["default", "minimization-search"]:
  1208. return
  1209. with c.test_case(name):
  1210. c.workflow(name)
  1211. c.test_parts(list(c.workflows.keys()), process)
  1212. def workflow_main(c: Composition, parser: WorkflowArgumentParser) -> None:
  1213. """Process various datasets in a memory-constrained environment in order
  1214. to exercise compaction/garbage collection and confirm no OOMs or thrashing."""
  1215. parser.add_argument(
  1216. "scenarios", nargs="*", default=None, help="run specified Scenarios"
  1217. )
  1218. args = parser.parse_args()
  1219. for scenario in shard_list(SCENARIOS, lambda scenario: scenario.name):
  1220. if shall_skip_scenario(scenario, args):
  1221. continue
  1222. if scenario.disabled:
  1223. print(f"+++ Scenario {scenario.name} is disabled, skipping.")
  1224. continue
  1225. c.override_current_testcase_name(f"Scenario '{scenario.name}'")
  1226. print(
  1227. f"+++ Running scenario {scenario.name} with materialized_memory={scenario.materialized_memory} and clusterd_memory={scenario.clusterd_memory} ..."
  1228. )
  1229. run_scenario(
  1230. c,
  1231. scenario,
  1232. materialized_memory=scenario.materialized_memory,
  1233. clusterd_memory=scenario.clusterd_memory,
  1234. )
  1235. def workflow_minimization_search(
  1236. c: Composition, parser: WorkflowArgumentParser
  1237. ) -> None:
  1238. """Find the minimal working memory configurations."""
  1239. parser.add_argument(
  1240. "scenarios", nargs="*", default=None, help="run specified Scenarios"
  1241. )
  1242. parser.add_argument(
  1243. "--materialized-memory-search-step",
  1244. default=0.2,
  1245. type=float,
  1246. )
  1247. parser.add_argument(
  1248. "--clusterd-memory-search-step",
  1249. default=0.2,
  1250. type=float,
  1251. )
  1252. parser.add_argument(
  1253. "--materialized-memory-lower-bound-in-gb",
  1254. default=1.5,
  1255. type=float,
  1256. )
  1257. parser.add_argument(
  1258. "--clusterd-memory-lower-bound-in-gb",
  1259. default=0.5,
  1260. type=float,
  1261. )
  1262. args = parser.parse_args()
  1263. if buildkite.is_in_buildkite():
  1264. test_analytics_config = create_test_analytics_config(c)
  1265. else:
  1266. test_analytics_config = create_dummy_test_analytics_config()
  1267. test_analytics = TestAnalyticsDb(test_analytics_config)
  1268. # will be updated to True at the end
  1269. test_analytics.builds.add_build_job(was_successful=False)
  1270. for scenario in shard_list(SCENARIOS, lambda scenario: scenario.name):
  1271. if shall_skip_scenario(scenario, args):
  1272. continue
  1273. if scenario.disabled:
  1274. print(f"+++ Scenario {scenario.name} is disabled, skipping.")
  1275. continue
  1276. c.override_current_testcase_name(f"Scenario '{scenario.name}'")
  1277. print(f"+++ Starting memory search for scenario {scenario.name}")
  1278. run_memory_search(
  1279. c,
  1280. scenario,
  1281. args.materialized_memory_search_step,
  1282. args.clusterd_memory_search_step,
  1283. args.materialized_memory_lower_bound_in_gb,
  1284. args.clusterd_memory_lower_bound_in_gb,
  1285. test_analytics,
  1286. )
  1287. try:
  1288. test_analytics.builds.update_build_job_success(True)
  1289. test_analytics.submit_updates()
  1290. print("Uploaded results.")
  1291. except Exception as e:
  1292. # An error during an upload must never cause the build to fail
  1293. test_analytics.on_upload_failed(e)
  1294. def shall_skip_scenario(scenario: Scenario, args: argparse.Namespace) -> bool:
  1295. return (
  1296. args.scenarios is not None
  1297. and len(args.scenarios) > 0
  1298. and scenario.name not in args.scenarios
  1299. )
  1300. def run_scenario(
  1301. c: Composition, scenario: Scenario, materialized_memory: str, clusterd_memory: str
  1302. ) -> None:
  1303. c.down(destroy_volumes=True)
  1304. with c.override(
  1305. Materialized(memory=materialized_memory),
  1306. Clusterd(memory=clusterd_memory),
  1307. ):
  1308. c.up(
  1309. "redpanda",
  1310. "materialized",
  1311. "postgres",
  1312. "mysql",
  1313. "clusterd",
  1314. {"name": "testdrive", "persistent": True},
  1315. )
  1316. c.sql(
  1317. "ALTER SYSTEM SET unsafe_enable_unorchestrated_cluster_replicas = true;",
  1318. port=6877,
  1319. user="mz_system",
  1320. )
  1321. c.sql(
  1322. """
  1323. CREATE CLUSTER clusterd REPLICAS (r1 (
  1324. STORAGECTL ADDRESSES ['clusterd:2100'],
  1325. STORAGE ADDRESSES ['clusterd:2103'],
  1326. COMPUTECTL ADDRESSES ['clusterd:2101'],
  1327. COMPUTE ADDRESSES ['clusterd:2102']
  1328. ))
  1329. """
  1330. )
  1331. testdrive_timeout_arg = "--default-timeout=5m"
  1332. statement_timeout = "> SET statement_timeout = '600s';\n"
  1333. c.testdrive(
  1334. statement_timeout + scenario.pre_restart, args=[testdrive_timeout_arg]
  1335. )
  1336. # Restart Mz to confirm that re-hydration is also bounded memory
  1337. c.kill("materialized", "clusterd")
  1338. c.up("materialized", "clusterd")
  1339. c.testdrive(
  1340. statement_timeout + scenario.post_restart, args=[testdrive_timeout_arg]
  1341. )
  1342. def try_run_scenario(
  1343. c: Composition, scenario: Scenario, materialized_memory: str, clusterd_memory: str
  1344. ) -> bool:
  1345. try:
  1346. run_scenario(c, scenario, materialized_memory, clusterd_memory)
  1347. return True
  1348. except:
  1349. return False
  1350. def run_memory_search(
  1351. c: Composition,
  1352. scenario: Scenario,
  1353. materialized_search_step_in_gb: float,
  1354. clusterd_search_step_in_gb: float,
  1355. materialized_memory_lower_bound_in_gb: float,
  1356. clusterd_memory_lower_bound_in_gb: float,
  1357. test_analytics: TestAnalyticsDb,
  1358. ) -> None:
  1359. assert materialized_search_step_in_gb > 0 or clusterd_search_step_in_gb > 0
  1360. materialized_memory = scenario.materialized_memory
  1361. clusterd_memory = scenario.clusterd_memory
  1362. none_minimization_target = "none"
  1363. search_entry = BoundedMemoryMinimalSearchEntry(
  1364. scenario_name=scenario.name,
  1365. tested_memory_mz_in_gb=_get_memory_in_gb(materialized_memory),
  1366. tested_memory_clusterd_in_gb=_get_memory_in_gb(clusterd_memory),
  1367. )
  1368. test_analytics.bounded_memory_search.add_entry(
  1369. BOUNDED_MEMORY_FRAMEWORK_VERSION,
  1370. search_entry,
  1371. minimization_target=none_minimization_target,
  1372. flush=True,
  1373. )
  1374. test_analytics.bounded_memory_search.update_status(
  1375. search_entry,
  1376. minimization_target=none_minimization_target,
  1377. status=BOUNDED_MEMORY_STATUS_CONFIGURED,
  1378. flush=True,
  1379. )
  1380. if materialized_search_step_in_gb > 0:
  1381. materialized_memory, clusterd_memory = find_minimal_memory(
  1382. c,
  1383. test_analytics,
  1384. scenario,
  1385. initial_materialized_memory=materialized_memory,
  1386. initial_clusterd_memory=clusterd_memory,
  1387. reduce_materialized_memory_by_gb=materialized_search_step_in_gb,
  1388. reduce_clusterd_memory_by_gb=0,
  1389. materialized_memory_lower_bound_in_gb=materialized_memory_lower_bound_in_gb,
  1390. clusterd_memory_lower_bound_in_gb=clusterd_memory_lower_bound_in_gb,
  1391. )
  1392. if clusterd_search_step_in_gb > 0:
  1393. materialized_memory, clusterd_memory = find_minimal_memory(
  1394. c,
  1395. test_analytics,
  1396. scenario,
  1397. initial_materialized_memory=materialized_memory,
  1398. initial_clusterd_memory=clusterd_memory,
  1399. reduce_materialized_memory_by_gb=0,
  1400. reduce_clusterd_memory_by_gb=clusterd_search_step_in_gb,
  1401. materialized_memory_lower_bound_in_gb=materialized_memory_lower_bound_in_gb,
  1402. clusterd_memory_lower_bound_in_gb=clusterd_memory_lower_bound_in_gb,
  1403. )
  1404. print(f"Found minimal memory for scenario {scenario.name}:")
  1405. print(
  1406. f"* materialized_memory={materialized_memory} (specified was: {scenario.materialized_memory})"
  1407. )
  1408. print(
  1409. f"* clusterd_memory={clusterd_memory} (specified was: {scenario.clusterd_memory})"
  1410. )
  1411. print("Consider adding some buffer to avoid flakiness.")
  1412. def find_minimal_memory(
  1413. c: Composition,
  1414. test_analytics: TestAnalyticsDb,
  1415. scenario: Scenario,
  1416. initial_materialized_memory: str,
  1417. initial_clusterd_memory: str,
  1418. reduce_materialized_memory_by_gb: float,
  1419. reduce_clusterd_memory_by_gb: float,
  1420. materialized_memory_lower_bound_in_gb: float,
  1421. clusterd_memory_lower_bound_in_gb: float,
  1422. ) -> tuple[str, str]:
  1423. if reduce_materialized_memory_by_gb > 0 and reduce_clusterd_memory_by_gb > 0:
  1424. raise RuntimeError(
  1425. "Cannot reduce both materialized and clusterd memory at once"
  1426. )
  1427. elif reduce_materialized_memory_by_gb >= 0.1:
  1428. minimalization_target = "materialized_memory"
  1429. elif reduce_clusterd_memory_by_gb >= 0.1:
  1430. minimalization_target = "clusterd_memory"
  1431. else:
  1432. raise RuntimeError("No valid reduction set")
  1433. materialized_memory = initial_materialized_memory
  1434. clusterd_memory = initial_clusterd_memory
  1435. materialized_memory_steps = [materialized_memory]
  1436. clusterd_memory_steps = [clusterd_memory]
  1437. while True:
  1438. new_materialized_memory = _reduce_memory(
  1439. materialized_memory,
  1440. reduce_materialized_memory_by_gb,
  1441. materialized_memory_lower_bound_in_gb,
  1442. )
  1443. new_clusterd_memory = _reduce_memory(
  1444. clusterd_memory,
  1445. reduce_clusterd_memory_by_gb,
  1446. clusterd_memory_lower_bound_in_gb,
  1447. )
  1448. if new_materialized_memory is None or new_clusterd_memory is None:
  1449. # limit undercut
  1450. break
  1451. scenario_desc = f"{scenario.name} with materialized_memory={new_materialized_memory} and clusterd_memory={new_clusterd_memory}"
  1452. search_entry = BoundedMemoryMinimalSearchEntry(
  1453. scenario_name=scenario.name,
  1454. tested_memory_mz_in_gb=_get_memory_in_gb(new_materialized_memory),
  1455. tested_memory_clusterd_in_gb=_get_memory_in_gb(new_clusterd_memory),
  1456. )
  1457. test_analytics.bounded_memory_search.add_entry(
  1458. BOUNDED_MEMORY_FRAMEWORK_VERSION,
  1459. search_entry,
  1460. minimization_target=minimalization_target,
  1461. flush=True,
  1462. )
  1463. print(f"Trying scenario {scenario_desc}")
  1464. success = try_run_scenario(
  1465. c,
  1466. scenario,
  1467. materialized_memory=new_materialized_memory,
  1468. clusterd_memory=new_clusterd_memory,
  1469. )
  1470. if success:
  1471. print(f"Scenario {scenario_desc} succeeded.")
  1472. materialized_memory = new_materialized_memory
  1473. clusterd_memory = new_clusterd_memory
  1474. materialized_memory_steps.append(new_materialized_memory)
  1475. clusterd_memory_steps.append(new_clusterd_memory)
  1476. test_analytics.bounded_memory_search.update_status(
  1477. search_entry,
  1478. status=BOUNDED_MEMORY_STATUS_SUCCESS,
  1479. minimization_target=minimalization_target,
  1480. flush=True,
  1481. )
  1482. else:
  1483. print(f"Scenario {scenario_desc} failed.")
  1484. test_analytics.bounded_memory_search.update_status(
  1485. search_entry,
  1486. status=BOUNDED_MEMORY_STATUS_FAILURE,
  1487. minimization_target=minimalization_target,
  1488. flush=True,
  1489. )
  1490. break
  1491. if (
  1492. materialized_memory < initial_materialized_memory
  1493. or clusterd_memory < initial_clusterd_memory
  1494. ):
  1495. print(f"Validating again the memory configuration for {scenario.name}")
  1496. materialized_memory, clusterd_memory = _validate_new_memory_configuration(
  1497. c,
  1498. scenario,
  1499. materialized_memory,
  1500. clusterd_memory,
  1501. materialized_memory_steps,
  1502. clusterd_memory_steps,
  1503. )
  1504. return materialized_memory, clusterd_memory
  1505. def _validate_new_memory_configuration(
  1506. c: Composition,
  1507. scenario: Scenario,
  1508. materialized_memory: str,
  1509. clusterd_memory: str,
  1510. materialized_memory_steps: list[str],
  1511. clusterd_memory_steps: list[str],
  1512. ) -> tuple[str, str]:
  1513. success = try_run_scenario(
  1514. c,
  1515. scenario,
  1516. materialized_memory=materialized_memory,
  1517. clusterd_memory=clusterd_memory,
  1518. )
  1519. scenario_desc = f"{scenario.name} with materialized_memory={materialized_memory} and clusterd_memory={clusterd_memory}"
  1520. if success:
  1521. print(f"Successfully validated {scenario_desc}")
  1522. else:
  1523. print(f"Validation of {scenario_desc} failed")
  1524. assert len(materialized_memory_steps) > 1 and len(clusterd_memory_steps) > 1
  1525. materialized_memory = materialized_memory_steps[-2]
  1526. clusterd_memory = clusterd_memory_steps[-2]
  1527. print(
  1528. f"Going back one step to materialized_memory={materialized_memory} and clusterd_memory={clusterd_memory}"
  1529. )
  1530. return materialized_memory, clusterd_memory
  1531. def _reduce_memory(
  1532. memory_spec: str, reduce_by_gb: float, lower_bound_in_gb: float
  1533. ) -> str | None:
  1534. if math.isclose(reduce_by_gb, 0.0, abs_tol=0.01):
  1535. # allow staying at the same value
  1536. return memory_spec
  1537. current_gb = _get_memory_in_gb(memory_spec)
  1538. if math.isclose(current_gb, lower_bound_in_gb, abs_tol=0.01):
  1539. # lower bound already reached
  1540. return None
  1541. new_gb = current_gb - reduce_by_gb
  1542. if new_gb < lower_bound_in_gb:
  1543. new_gb = lower_bound_in_gb
  1544. return f"{round(new_gb, 2)}Gb"
  1545. def _get_memory_in_gb(memory_spec: str) -> float:
  1546. if not memory_spec.endswith("Gb"):
  1547. raise RuntimeError(f"Unsupported memory specification: {memory_spec}")
  1548. return float(memory_spec.removesuffix("Gb"))