You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: ydb/docs/en/core/dev/example-app/python/index.md
+59-43Lines changed: 59 additions & 43 deletions
Original file line number
Diff line number
Diff line change
@@ -61,9 +61,25 @@ App code snippet for driver initialization:
61
61
62
62
{% endlist %}
63
63
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
+
64
80
{% include [create_table.md](../_includes/steps/02_create_table.md) %}
65
81
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:
67
83
68
84
{% list tabs %}
69
85
@@ -74,7 +90,7 @@ To execute YQL queries, use the `pool.execute_with_retries()` method. For exampl
74
90
print("\nCreating table series...")
75
91
pool.execute_with_retries(
76
92
"""
77
-
CREATE table `series` (
93
+
CREATE TABLE `series` (
78
94
`series_id` Int64,
79
95
`title` Utf8,
80
96
`series_info` Utf8,
@@ -87,7 +103,7 @@ To execute YQL queries, use the `pool.execute_with_retries()` method. For exampl
87
103
print("\nCreating table seasons...")
88
104
pool.execute_with_retries(
89
105
"""
90
-
CREATE table `seasons` (
106
+
CREATE TABLE `seasons` (
91
107
`series_id` Int64,
92
108
`season_id` Int64,
93
109
`title` Utf8,
@@ -101,7 +117,7 @@ To execute YQL queries, use the `pool.execute_with_retries()` method. For exampl
101
117
print("\nCreating table episodes...")
102
118
pool.execute_with_retries(
103
119
"""
104
-
CREATE table `episodes` (
120
+
CREATE TABLE `episodes` (
105
121
`series_id` Int64,
106
122
`season_id` Int64,
107
123
`episode_id` Int64,
@@ -120,7 +136,7 @@ To execute YQL queries, use the `pool.execute_with_retries()` method. For exampl
120
136
print("\nCreating table series...")
121
137
await pool.execute_with_retries(
122
138
"""
123
-
CREATE table `series` (
139
+
CREATE TABLE `series` (
124
140
`series_id` Int64,
125
141
`title` Utf8,
126
142
`series_info` Utf8,
@@ -133,7 +149,7 @@ To execute YQL queries, use the `pool.execute_with_retries()` method. For exampl
133
149
print("\nCreating table seasons...")
134
150
await pool.execute_with_retries(
135
151
"""
136
-
CREATE table `seasons` (
152
+
CREATE TABLE `seasons` (
137
153
`series_id` Int64,
138
154
`season_id` Int64,
139
155
`title` Utf8,
@@ -147,7 +163,7 @@ To execute YQL queries, use the `pool.execute_with_retries()` method. For exampl
147
163
print("\nCreating table episodes...")
148
164
await pool.execute_with_retries(
149
165
"""
150
-
CREATE table `episodes` (
166
+
CREATE TABLE `episodes` (
151
167
`series_id` Int64,
152
168
`season_id` Int64,
153
169
`episode_id` Int64,
@@ -161,7 +177,6 @@ To execute YQL queries, use the `pool.execute_with_retries()` method. For exampl
161
177
162
178
{% endlist %}
163
179
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.
165
180
166
181
{% include [steps/03_write_queries.md](../_includes/steps/03_write_queries.md) %}
167
182
@@ -197,7 +212,7 @@ Code snippet for data insert/update:
197
212
198
213
{% include [steps/04_query_processing.md](../_includes/steps/04_query_processing.md) %}
199
214
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.
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:
275
293
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`|
284
303
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 %}
286
305
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:
288
311
289
312
{% list tabs %}
290
313
@@ -306,8 +329,8 @@ A code snippet demonstrating the possibility of using parameterized queries:
306
329
""",
307
330
{
308
331
"$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
311
334
},
312
335
)
313
336
@@ -336,9 +359,9 @@ A code snippet demonstrating the possibility of using parameterized queries:
336
359
WHERE series_id = $seriesId AND season_id = $seasonId AND episode_id = $episodeId;
337
360
""",
338
361
{
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
342
365
},
343
366
)
344
367
@@ -352,7 +375,7 @@ A code snippet demonstrating the possibility of using parameterized queries:
352
375
353
376
{% endlist %}
354
377
355
-
The above code snippet outputs text to the console:
378
+
The code snippet above outputs the following text to the console:
356
379
357
380
```bash
358
381
> select_prepared_transaction:
@@ -361,20 +384,17 @@ The above code snippet outputs text to the console:
361
384
362
385
{% include [transaction_control.md](../_includes/steps/10_transaction_control.md) %}
363
386
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.
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).
374
396
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.
378
398
379
399
{% list tabs %}
380
400
@@ -394,10 +414,7 @@ For convenience, the result of the `tx.execute()` function is presented as a con
394
414
395
415
{% endlist %}
396
416
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()`:
401
418
402
419
{% list tabs %}
403
420
@@ -481,12 +498,11 @@ A code snippet demonstrating the explicit use of `transaction().begin()` and `tx
481
498
482
499
{% endlist %}
483
500
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.
486
502
487
-
## Huge Selects {#huge-selects}
503
+
## Iterating over query results {#iterating}
488
504
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.
490
506
491
507
Example of a `SELECT` with unlimited data and implicit transaction control:
0 commit comments