Skip to content

Commit f8f5151

Browse files
author
Saurabh Badenkal
committed
Add anti-pattern warnings + best practices section to sql_examples.py
New section 32: IMPORTANT Anti-Patterns & Best Practices - Cartesian products (FROM a, b without ON) -- AVOID - Leading-wildcard LIKE -- forces full table scans - No filter on large system tables -- returns max rows - SELECT * on wide tables -- transfers 260+ columns - Deep JOINs without TOP -- always use TOP N Also: toned down JOIN depth messaging to 'no limit (tested 15)' instead of promoting 15-table JOINs as a feature. Fixed duplicate SQL vs OData table in examples. 34 sections, 1194 lines. 756 unit tests passing.
1 parent 50cf7d7 commit f8f5151

1 file changed

Lines changed: 54 additions & 7 deletions

File tree

examples/advanced/sql_examples.py

Lines changed: 54 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -864,10 +864,12 @@ def _run_examples(client):
864864
# ==============================================================
865865
# 28. Deep JOINs (5-8 tables)
866866
# ==============================================================
867-
heading(28, "Deep JOINs (5-8 Tables) -- Built-In Tables")
867+
heading(28, "Deep JOINs (5+ Tables) -- No Depth Limit")
868868
print(
869-
"SQL JOINs support at least 8 tables with no server depth limit.\n"
870-
"Performance stays consistent (~0.7s for 8-table JOINs)."
869+
"SQL JOINs have no server-imposed depth limit (tested up to 15\n"
870+
"tables). Each JOIN uses indexed foreign key lookups, so\n"
871+
"performance stays consistent. Most real-world queries use\n"
872+
"2-4 tables; deeper JOINs are available when needed."
871873
)
872874

873875
sql = (
@@ -999,7 +1001,7 @@ def _run_examples(client):
9991001
+-------------------------------+------------------------+------------------------+
10001002
| Read data | YES | YES |
10011003
| Write data | NO (read-only) | YES (create/update/del)|
1002-
| JOIN depth | 15+ tables (no limit) | $expand 10-level max |
1004+
| JOIN depth | No limit (tested 15) | $expand 10-level max |
10031005
| JOIN types | INNER, LEFT | $expand (single-valued)|
10041006
| Aggregates (COUNT, SUM, etc.) | YES (server-side) | Limited ($apply) |
10051007
| GROUP BY | YES (server-side) | Via $apply (complex) |
@@ -1070,9 +1072,54 @@ def _run_examples(client):
10701072
print(f" OData $expand: error ({odata_time:.2f}s): {e}")
10711073

10721074
# ==============================================================
1073-
# 32. Summary
1075+
# 32. Anti-Patterns & Best Practices
10741076
# ==============================================================
1075-
heading(32, "Summary -- SQL Capabilities Reference")
1077+
heading(32, "IMPORTANT: Anti-Patterns & Best Practices")
1078+
print("""
1079+
=== ANTI-PATTERNS (avoid these -- they hurt shared database performance) ===
1080+
1081+
1. CARTESIAN PRODUCTS (FROM table1, table2 without ON)
1082+
BAD: SELECT a.name, c.fullname FROM account a, contact c
1083+
WHY: Produces rows_a * rows_b intermediate rows. With 5000-row tables,
1084+
that's 25 MILLION rows the server must process before capping at 5000.
1085+
FIX: Always use explicit JOIN with ON clause.
1086+
1087+
2. LEADING-WILDCARD LIKE (LIKE '%value')
1088+
BAD: SELECT name FROM account WHERE name LIKE '%corp'
1089+
WHY: Forces a FULL TABLE SCAN -- cannot use indexes. On tables with
1090+
millions of rows, this monopolizes shared database resources and
1091+
slows down OTHER users' queries on the same database.
1092+
FIX: Use trailing wildcards: LIKE 'corp%' (uses indexes efficiently).
1093+
If you must search mid-string, add TOP to limit scan scope.
1094+
1095+
3. NO FILTER ON LARGE SYSTEM TABLES
1096+
BAD: SELECT name FROM role
1097+
WHY: System tables (role, asyncoperation, sdkmessageprocessingstep)
1098+
can have 5000+ rows. Unfiltered queries return max rows.
1099+
FIX: Always add WHERE filters and TOP when querying system tables.
1100+
1101+
4. SELECT * ON WIDE TABLES
1102+
BAD: SELECT * FROM account (307 columns!)
1103+
WHY: The SDK auto-expands * into all 260+ non-virtual columns.
1104+
Every column is transferred over the network.
1105+
FIX: List only the columns you need: SELECT name, revenue FROM account
1106+
1107+
5. DEEP JOINS WITHOUT TOP
1108+
OK: SELECT TOP 100 a.name, ... FROM account a JOIN ... (15 tables)
1109+
BAD: SELECT a.name, ... FROM account a JOIN ... (15 tables, no TOP)
1110+
WHY: Deep JOINs are safe with proper FK relationships and TOP.
1111+
Without TOP, the server processes up to 5000 rows across all joins.
1112+
FIX: Always include TOP N for multi-table JOINs.
1113+
1114+
The SDK's guardrails automatically warn on patterns #1 and #2.
1115+
The server enforces a 5000-row cap on all queries (pattern #3 and #5).
1116+
Pattern #4 is handled by the SDK's SELECT * auto-expansion.
1117+
""")
1118+
1119+
# ==============================================================
1120+
# 33. Summary
1121+
# ==============================================================
1122+
heading(33, "Summary -- SQL Capabilities Reference")
10761123
print("""
10771124
+-------------------------------+----------+----------------------------------------+
10781125
| Feature | SQL | Notes / SDK Fallback |
@@ -1125,7 +1172,7 @@ def _run_examples(client):
11251172
""")
11261173

11271174
finally:
1128-
heading(33, "Cleanup")
1175+
heading(34, "Cleanup")
11291176
for tbl in [child_table, parent_table]:
11301177
log_call(f"client.tables.delete('{tbl}')")
11311178
try:

0 commit comments

Comments
 (0)