Skip to content

Commit 39c9f7e

Browse files
vgvolegblinkov
andauthored
Apply suggestions from code review
Co-authored-by: Ivan Blinkov <ivan@blinkov.ru>
1 parent e772ec7 commit 39c9f7e

File tree

2 files changed

+62
-46
lines changed
  • ydb/docs

2 files changed

+62
-46
lines changed

ydb/docs/en/core/dev/example-app/python/index.md

Lines changed: 59 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,25 @@ App code snippet for driver initialization:
6161

6262
{% endlist %}
6363

64+
## Executing queries
65+
66+
The {{ ydb-short-name }} Python SDK provides two primary methods for executing queries, each with different properties and use cases:
67+
68+
* `pool.execute_with_retries`:
69+
* Buffers the entire result set in client memory.
70+
* Automatically retries execution in case of retriable issues.
71+
* Does not allow specifying a transaction execution mode.
72+
* Recommended for one-off queries that are expected to produce small result sets.
73+
74+
* `tx.execute`:
75+
* Returns an iterator over the query results, allowing processing of results that may not fit into client memory.
76+
* Retries must be handled manually.
77+
* Allows specifying a transaction execution mode.
78+
* Recommended for scenarios where `pool.execute_with_retries` is insufficient.
79+
6480
{% include [create_table.md](../_includes/steps/02_create_table.md) %}
6581

66-
To execute YQL queries, use the `pool.execute_with_retries()` method. For example, it is possible to create table:
82+
To execute `CREATE TABLE` queries, use the `pool.execute_with_retries()` method:
6783

6884
{% list tabs %}
6985

@@ -74,7 +90,7 @@ To execute YQL queries, use the `pool.execute_with_retries()` method. For exampl
7490
print("\nCreating table series...")
7591
pool.execute_with_retries(
7692
"""
77-
CREATE table `series` (
93+
CREATE TABLE `series` (
7894
`series_id` Int64,
7995
`title` Utf8,
8096
`series_info` Utf8,
@@ -87,7 +103,7 @@ To execute YQL queries, use the `pool.execute_with_retries()` method. For exampl
87103
print("\nCreating table seasons...")
88104
pool.execute_with_retries(
89105
"""
90-
CREATE table `seasons` (
106+
CREATE TABLE `seasons` (
91107
`series_id` Int64,
92108
`season_id` Int64,
93109
`title` Utf8,
@@ -101,7 +117,7 @@ To execute YQL queries, use the `pool.execute_with_retries()` method. For exampl
101117
print("\nCreating table episodes...")
102118
pool.execute_with_retries(
103119
"""
104-
CREATE table `episodes` (
120+
CREATE TABLE `episodes` (
105121
`series_id` Int64,
106122
`season_id` Int64,
107123
`episode_id` Int64,
@@ -120,7 +136,7 @@ To execute YQL queries, use the `pool.execute_with_retries()` method. For exampl
120136
print("\nCreating table series...")
121137
await pool.execute_with_retries(
122138
"""
123-
CREATE table `series` (
139+
CREATE TABLE `series` (
124140
`series_id` Int64,
125141
`title` Utf8,
126142
`series_info` Utf8,
@@ -133,7 +149,7 @@ To execute YQL queries, use the `pool.execute_with_retries()` method. For exampl
133149
print("\nCreating table seasons...")
134150
await pool.execute_with_retries(
135151
"""
136-
CREATE table `seasons` (
152+
CREATE TABLE `seasons` (
137153
`series_id` Int64,
138154
`season_id` Int64,
139155
`title` Utf8,
@@ -147,7 +163,7 @@ To execute YQL queries, use the `pool.execute_with_retries()` method. For exampl
147163
print("\nCreating table episodes...")
148164
await pool.execute_with_retries(
149165
"""
150-
CREATE table `episodes` (
166+
CREATE TABLE `episodes` (
151167
`series_id` Int64,
152168
`season_id` Int64,
153169
`episode_id` Int64,
@@ -161,7 +177,6 @@ To execute YQL queries, use the `pool.execute_with_retries()` method. For exampl
161177

162178
{% endlist %}
163179

164-
The function `pool.execute_with_retries(query)`, unlike `tx.execute()`, loads the result of the query into memory before returning it to the client. This eliminates the need to use special constructs to control the iterator, but it is necessary to use this method with caution for large `SELECT` queries. More information about streams will be discussed below.
165180

166181
{% include [steps/03_write_queries.md](../_includes/steps/03_write_queries.md) %}
167182

@@ -197,7 +212,7 @@ Code snippet for data insert/update:
197212

198213
{% include [steps/04_query_processing.md](../_includes/steps/04_query_processing.md) %}
199214

200-
To execute YQL queries, it is often enough to use the already familiar `pool.execute_with_retries()` method.
215+
To execute YQL queries, the `pool.execute_with_retries()` method is often sufficient.
201216

202217
{% list tabs %}
203218

@@ -268,23 +283,31 @@ series, Id: 1, title: IT Crowd, Release date: 2006-02-03
268283

269284
## Parameterized queries {#param-queries}
270285

271-
To execute parameterized queries in the `pool.execute_with_retries()` method (or `tx.execute()`, which will be shown in the next section) it is necessary to pass a dictionary with parameters of a special type, where the key is the parameter name, and the value can be one of the following:
272-
1. The usual value;
273-
2. Tuple with value and type;
274-
3. A special type `ydb.TypedValue(value=value, value_type=value_type)`.
286+
For parameterized query execution, `pool.execute_with_retries()` and `tx.execute()` behave similarly. To execute parameterized queries, you need to pass a dictionary with parameters to one of these functions, where each key is the parameter name, and the value can be one of the following:
287+
288+
1. A value of a basic Python type
289+
2. A tuple containing the value and its type
290+
3. A special type, `ydb.TypedValue(value=value, value_type=value_type)`
291+
292+
If you specify a value without an explicit type, the conversion takes place according to the following rules:
275293

276-
If you specify a value without a type, the conversion takes place according to the following rules:
277-
* `int` -> `ydb.PrimitiveType.Int64`
278-
* `float` -> `ydb.PrimitiveType.Double`
279-
* `str` -> `ydb.PrimitiveType.Utf8`
280-
* `bytes` -> `ydb.PrimitiveType.String`
281-
* `bool` -> `ydb.PrimitiveType.Bool`
282-
* `list` -> `ydb.ListType`
283-
* `dict` -> `ydb.DictType`
294+
| Python type | {{ ydb-short-name }} type |
295+
|------------|------------------------------|
296+
| `int` | `ydb.PrimitiveType.Int64` |
297+
| `float` | `ydb.PrimitiveType.Double` |
298+
| `str` | `ydb.PrimitiveType.Utf8` |
299+
| `bytes` | `ydb.PrimitiveType.String` |
300+
| `bool` | `ydb.PrimitiveType.Bool` |
301+
| `list` | `ydb.ListType` |
302+
| `dict` | `ydb.DictType` |
284303

285-
Automatic conversion of lists and dictionaries is possible only in the case of homogeneous structures, the type of nested value will be calculated recursively according to the above rules.
304+
{% note warning %}
286305

287-
A code snippet demonstrating the possibility of using parameterized queries:
306+
Automatic conversion of lists and dictionaries is possible only if the structures are homogeneous. The type of nested values will be determined recursively according to the rules explained above.
307+
308+
{% endnote %}
309+
310+
A code snippet demonstrating the parameterized query execution:
288311

289312
{% list tabs %}
290313

@@ -306,8 +329,8 @@ A code snippet demonstrating the possibility of using parameterized queries:
306329
""",
307330
{
308331
"$seriesId": series_id, # data type could be defined implicitly
309-
"$seasonId": (season_id, ydb.PrimitiveType.Int64), # could be defined via tuple
310-
"$episodeId": ydb.TypedValue(episode_id, ydb.PrimitiveType.Int64), # could be defined via special class
332+
"$seasonId": (season_id, ydb.PrimitiveType.Int64), # could be defined via a tuple
333+
"$episodeId": ydb.TypedValue(episode_id, ydb.PrimitiveType.Int64), # could be defined via a special class
311334
},
312335
)
313336

@@ -336,9 +359,9 @@ A code snippet demonstrating the possibility of using parameterized queries:
336359
WHERE series_id = $seriesId AND season_id = $seasonId AND episode_id = $episodeId;
337360
""",
338361
{
339-
"$seriesId": series_id, # could be defined implicit
340-
"$seasonId": (season_id, ydb.PrimitiveType.Int64), # could be defined via tuple
341-
"$episodeId": ydb.TypedValue(episode_id, ydb.PrimitiveType.Int64), # could be defined via special class
362+
"$seriesId": series_id, # could be defined implicitly
363+
"$seasonId": (season_id, ydb.PrimitiveType.Int64), # could be defined via a tuple
364+
"$episodeId": ydb.TypedValue(episode_id, ydb.PrimitiveType.Int64), # could be defined via a special class
342365
},
343366
)
344367

@@ -352,7 +375,7 @@ A code snippet demonstrating the possibility of using parameterized queries:
352375

353376
{% endlist %}
354377

355-
The above code snippet outputs text to the console:
378+
The code snippet above outputs the following text to the console:
356379

357380
```bash
358381
> select_prepared_transaction:
@@ -361,20 +384,17 @@ The above code snippet outputs text to the console:
361384

362385
{% include [transaction_control.md](../_includes/steps/10_transaction_control.md) %}
363386

364-
The `session.transaction().execute()` method can also be used to execute YQL queries.
365-
This method, unlike `pool.execute_with_retries`, allows you to explicitly control the execution of transactions and configure the needed transaction mode using the `TxControl` class.
387+
The `session.transaction().execute()` method can also be used to execute YQL queries. Unlike `pool.execute_with_retries`, this method allows explicit control of transaction execution by configuring the desired transaction mode using the `TxControl` class.
366388

367389
Available transaction modes:
368390
* `ydb.QuerySerializableReadWrite()` (default);
369391
* `ydb.QueryOnlineReadOnly(allow_inconsistent_reads=False)`;
370392
* `ydb.QuerySnapshotReadOnly()`;
371393
* `ydb.QueryStaleReadOnly()`.
372394

373-
For more information about transaction modes, see [YDB docs](https://ydb.tech/docs/en/concepts/transactions#modes)
395+
For more information about transaction modes, see [{#T}](../../../concepts/transactions.md#modes).
374396

375-
The result of executing `tx.execute()` is an iterator. The iterator allows you to read an unlimited number of rows and a volume of data without loading the entire result into memory.
376-
However, in order to correctly save the state of the transaction on the `ydb` side, the iterator must be read to the end after each request.
377-
For convenience, the result of the `tx.execute()` function is presented as a context manager that scrolls through the iterator to the end after exiting.
397+
The result of executing `tx.execute()` is an iterator. This iterator allows you to read result rows without loading the entire result set into memory. However, the iterator must be read to the end after each request to correctly maintain the transaction state on the {{ ydb-short-name }} server side. For convenience, the result of the `tx.execute()` function can be used as a context manager that automatically iterates to the end upon exit.
378398

379399
{% list tabs %}
380400

@@ -394,10 +414,7 @@ For convenience, the result of the `tx.execute()` function is presented as a con
394414

395415
{% endlist %}
396416

397-
In the code snippet below, the transaction is executed using the `transaction().execute()` method. The transaction mode is set to `ydb.QuerySerializableReadWrite()`.
398-
The request body is described using YQL syntax and is passed to the `execute` method as the parameter.
399-
400-
A code snippet demonstrating the explicit use of `transaction().begin()` and `tx.commit()`:
417+
The code snippet below demonstrates the explicit use of `transaction().begin()` and `tx.commit()` with the transaction mode set to `ydb.QuerySerializableReadWrite()`:
401418

402419
{% list tabs %}
403420

@@ -481,12 +498,11 @@ A code snippet demonstrating the explicit use of `transaction().begin()` and `tx
481498

482499
{% endlist %}
483500

484-
However, it is worth remembering that a transaction can be opened implicitly at the first request. It could be commited automatically with the explicit indication of the `commit_tx=True` flag.
485-
Implicit transaction management is preferable because it requires fewer server calls. An example of implicit control will be demonstrated in the next block.
501+
However, a transaction can be opened implicitly with the first request and can be committed automatically by setting the `commit_tx=True` flag in arguments. Implicit transaction management is preferable because it requires fewer server calls.
486502

487-
## Huge Selects {#huge-selects}
503+
## Iterating over query results {#iterating}
488504

489-
To perform `SELECT` operations with an unlimited number of found rows, you must also use the `transaction().execute(query)` method. As mentioned above, the result of the work is an iterator - unlike `pool.execute_with_retries(query)`, it allows you to go through the selection without first loading it into memory.
505+
If a `SELECT` query is expected to return a potentially large number of rows, it is recommended to use the `tx.execute` method instead of `pool.execute_with_retries` to avoid excessive memory consumption on the client side. Instead of buffering the entire result set into memory, `tx.execute` returns an iterator for each top-level `SELECT` statement in the query.
490506

491507
Example of a `SELECT` with unlimited data and implicit transaction control:
492508

ydb/docs/ru/core/dev/example-app/python/index.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ python3 -m pip install iso8601
7474
print("\nCreating table series...")
7575
pool.execute_with_retries(
7676
"""
77-
CREATE table `series` (
77+
CREATE TABLE `series` (
7878
`series_id` Int64,
7979
`title` Utf8,
8080
`series_info` Utf8,
@@ -87,7 +87,7 @@ python3 -m pip install iso8601
8787
print("\nCreating table seasons...")
8888
pool.execute_with_retries(
8989
"""
90-
CREATE table `seasons` (
90+
CREATE TABLE `seasons` (
9191
`series_id` Int64,
9292
`season_id` Int64,
9393
`title` Utf8,
@@ -101,7 +101,7 @@ python3 -m pip install iso8601
101101
print("\nCreating table episodes...")
102102
pool.execute_with_retries(
103103
"""
104-
CREATE table `episodes` (
104+
CREATE TABLE `episodes` (
105105
`series_id` Int64,
106106
`season_id` Int64,
107107
`episode_id` Int64,

0 commit comments

Comments
 (0)