Skip to content

Instantly share code, notes, and snippets.

@0x0L
Last active November 8, 2021 09:40
Show Gist options
  • Save 0x0L/3d55d47f6329eb0d7e7a46d1c895b5be to your computer and use it in GitHub Desktop.
Save 0x0L/3d55d47f6329eb0d7e7a46d1c895b5be to your computer and use it in GitHub Desktop.
asyncpg / apache arrow
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"id": "ae35c501-093f-4d82-9ac5-bfb3a2caee9e",
"metadata": {},
"outputs": [],
"source": [
"%load_ext cython"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "65099ae5-0f04-48dd-89c7-330af2aec8be",
"metadata": {},
"outputs": [],
"source": [
"import asyncpg\n",
"import psycopg\n",
"import pandas as pd\n",
"import pyarrow as pa"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "4806649a-39b2-4af1-b6de-407ab5ce69a2",
"metadata": {},
"outputs": [],
"source": [
"dsn = 'postgres://postgres:postgres@localhost:55000/usda'\n",
"conn = await asyncpg.connect(dsn)"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "8fbf95c1-e3b8-467d-9f00-0b4a99a3de8b",
"metadata": {},
"outputs": [],
"source": [
"async def get_pandas(sql):\n",
" z = await conn.fetch(sql)\n",
" df = pd.DataFrame.from_records(z, columns=list(z[0].keys()))\n",
" return df"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "b181e23c-88b4-4a4a-9e82-7f4e453bad0d",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>schemaname</th>\n",
" <th>tablename</th>\n",
" <th>tableowner</th>\n",
" <th>tablespace</th>\n",
" <th>hasindexes</th>\n",
" <th>hasrules</th>\n",
" <th>hastriggers</th>\n",
" <th>rowsecurity</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>public</td>\n",
" <td>data_src</td>\n",
" <td>postgres</td>\n",
" <td>None</td>\n",
" <td>True</td>\n",
" <td>False</td>\n",
" <td>True</td>\n",
" <td>False</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>public</td>\n",
" <td>datsrcln</td>\n",
" <td>postgres</td>\n",
" <td>None</td>\n",
" <td>True</td>\n",
" <td>False</td>\n",
" <td>True</td>\n",
" <td>False</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>public</td>\n",
" <td>nut_data</td>\n",
" <td>postgres</td>\n",
" <td>None</td>\n",
" <td>True</td>\n",
" <td>False</td>\n",
" <td>True</td>\n",
" <td>False</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>public</td>\n",
" <td>fd_group</td>\n",
" <td>postgres</td>\n",
" <td>None</td>\n",
" <td>True</td>\n",
" <td>False</td>\n",
" <td>True</td>\n",
" <td>False</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>public</td>\n",
" <td>food_des</td>\n",
" <td>postgres</td>\n",
" <td>None</td>\n",
" <td>True</td>\n",
" <td>False</td>\n",
" <td>True</td>\n",
" <td>False</td>\n",
" </tr>\n",
" <tr>\n",
" <th>5</th>\n",
" <td>public</td>\n",
" <td>footnote</td>\n",
" <td>postgres</td>\n",
" <td>None</td>\n",
" <td>True</td>\n",
" <td>False</td>\n",
" <td>True</td>\n",
" <td>False</td>\n",
" </tr>\n",
" <tr>\n",
" <th>6</th>\n",
" <td>public</td>\n",
" <td>nutr_def</td>\n",
" <td>postgres</td>\n",
" <td>None</td>\n",
" <td>True</td>\n",
" <td>False</td>\n",
" <td>True</td>\n",
" <td>False</td>\n",
" </tr>\n",
" <tr>\n",
" <th>7</th>\n",
" <td>public</td>\n",
" <td>deriv_cd</td>\n",
" <td>postgres</td>\n",
" <td>None</td>\n",
" <td>True</td>\n",
" <td>False</td>\n",
" <td>True</td>\n",
" <td>False</td>\n",
" </tr>\n",
" <tr>\n",
" <th>8</th>\n",
" <td>public</td>\n",
" <td>src_cd</td>\n",
" <td>postgres</td>\n",
" <td>None</td>\n",
" <td>True</td>\n",
" <td>False</td>\n",
" <td>True</td>\n",
" <td>False</td>\n",
" </tr>\n",
" <tr>\n",
" <th>9</th>\n",
" <td>public</td>\n",
" <td>weight</td>\n",
" <td>postgres</td>\n",
" <td>None</td>\n",
" <td>True</td>\n",
" <td>False</td>\n",
" <td>True</td>\n",
" <td>False</td>\n",
" </tr>\n",
" <tr>\n",
" <th>10</th>\n",
" <td>public</td>\n",
" <td>minute_bars</td>\n",
" <td>postgres</td>\n",
" <td>None</td>\n",
" <td>False</td>\n",
" <td>False</td>\n",
" <td>False</td>\n",
" <td>False</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" schemaname tablename tableowner tablespace hasindexes hasrules \\\n",
"0 public data_src postgres None True False \n",
"1 public datsrcln postgres None True False \n",
"2 public nut_data postgres None True False \n",
"3 public fd_group postgres None True False \n",
"4 public food_des postgres None True False \n",
"5 public footnote postgres None True False \n",
"6 public nutr_def postgres None True False \n",
"7 public deriv_cd postgres None True False \n",
"8 public src_cd postgres None True False \n",
"9 public weight postgres None True False \n",
"10 public minute_bars postgres None False False \n",
"\n",
" hastriggers rowsecurity \n",
"0 True False \n",
"1 True False \n",
"2 True False \n",
"3 True False \n",
"4 True False \n",
"5 True False \n",
"6 True False \n",
"7 True False \n",
"8 True False \n",
"9 True False \n",
"10 False False "
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df = await get_pandas(\"select * from pg_catalog.pg_tables where schemaname = 'public'\")\n",
"df"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "8e8d373b-0a83-4a72-9576-db2d402d5422",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"<Record count=4464100>\n"
]
},
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>ordinal_position</th>\n",
" <th>column_name</th>\n",
" <th>column_default</th>\n",
" <th>is_nullable</th>\n",
" <th>udt_name</th>\n",
" <th>data_type</th>\n",
" <th>character_maximum_length</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>1</td>\n",
" <td>timestamp</td>\n",
" <td>None</td>\n",
" <td>YES</td>\n",
" <td>timestamp</td>\n",
" <td>timestamp without time zone</td>\n",
" <td>None</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>2</td>\n",
" <td>symbol</td>\n",
" <td>None</td>\n",
" <td>YES</td>\n",
" <td>int4</td>\n",
" <td>integer</td>\n",
" <td>None</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>3</td>\n",
" <td>open_price</td>\n",
" <td>None</td>\n",
" <td>YES</td>\n",
" <td>float4</td>\n",
" <td>real</td>\n",
" <td>None</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>4</td>\n",
" <td>high_price</td>\n",
" <td>None</td>\n",
" <td>YES</td>\n",
" <td>float4</td>\n",
" <td>real</td>\n",
" <td>None</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>5</td>\n",
" <td>low_price</td>\n",
" <td>None</td>\n",
" <td>YES</td>\n",
" <td>float4</td>\n",
" <td>real</td>\n",
" <td>None</td>\n",
" </tr>\n",
" <tr>\n",
" <th>5</th>\n",
" <td>6</td>\n",
" <td>close_price</td>\n",
" <td>None</td>\n",
" <td>YES</td>\n",
" <td>float4</td>\n",
" <td>real</td>\n",
" <td>None</td>\n",
" </tr>\n",
" <tr>\n",
" <th>6</th>\n",
" <td>7</td>\n",
" <td>volume</td>\n",
" <td>None</td>\n",
" <td>YES</td>\n",
" <td>int4</td>\n",
" <td>integer</td>\n",
" <td>None</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" ordinal_position column_name column_default is_nullable udt_name \\\n",
"0 1 timestamp None YES timestamp \n",
"1 2 symbol None YES int4 \n",
"2 3 open_price None YES float4 \n",
"3 4 high_price None YES float4 \n",
"4 5 low_price None YES float4 \n",
"5 6 close_price None YES float4 \n",
"6 7 volume None YES int4 \n",
"\n",
" data_type character_maximum_length \n",
"0 timestamp without time zone None \n",
"1 integer None \n",
"2 real None \n",
"3 real None \n",
"4 real None \n",
"5 real None \n",
"6 integer None "
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"tbl = 'minute_bars'\n",
"\n",
"c = await conn.fetchrow(f'select count(*) from {tbl}')\n",
"print(c)\n",
"\n",
"df = await get_pandas(f\"select ordinal_position, column_name, column_default, is_nullable, udt_name, data_type, character_maximum_length from information_schema.columns where table_name = '{tbl}'\")\n",
"df"
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "9b8fbe25-c64d-4188-b138-cac2828a3708",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"column_name\n",
"timestamp timestamp\n",
"symbol int4\n",
"open_price float4\n",
"high_price float4\n",
"low_price float4\n",
"close_price float4\n",
"volume int4\n",
"Name: udt_name, dtype: object"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"types = df.set_index('column_name').udt_name\n",
"types"
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "a80c10c1-0745-4f49-ba1e-eac3ce84db03",
"metadata": {},
"outputs": [],
"source": [
"_type_map = {\n",
" 'bpchar': pa.string(),\n",
" 'text': pa.string(),\n",
" 'int4': pa.int32(),\n",
" 'float8': pa.float64(),\n",
" 'float4': pa.float32(),\n",
" 'timestamp': pa.timestamp('us')\n",
"}\n",
"\n",
"_builder_map = {\n",
" 'bpchar': 'string',\n",
" 'text': 'string',\n",
" 'int4': 'int32',\n",
" 'float8': 'float64',\n",
" 'float4': 'float32',\n",
" 'timestamp': 'timestamp'\n",
"}"
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "f6bdd0c1-3b1f-4fef-9c69-3b38c5bd8814",
"metadata": {},
"outputs": [],
"source": [
"%%cython -3 -+ -c=-std=c++11 -c=-Wno-unused-variable --link-args=-std=c++11 -I/Users/xav/.condaenv/pq/lib/python3.10/site-packages/numpy/core/include\n",
"\n",
"cimport cython\n",
"\n",
"from libc.stdint cimport int16_t, int32_t, uint16_t, uint32_t, int64_t, uint64_t\n",
"\n",
"from libcpp.memory cimport shared_ptr\n",
"from libcpp.vector cimport vector\n",
"\n",
"from pyarrow.lib cimport *\n",
"\n",
"cdef extern from \"/Users/xav/src/asyncpg/asyncpg/pgproto/hton.h\":\n",
" cdef int16_t unpack_int16(const char *buf);\n",
" cdef uint16_t unpack_uint16(const char *buf);\n",
" cdef int32_t unpack_int32(const char *buf);\n",
" cdef uint32_t unpack_uint32(const char *buf);\n",
" cdef int64_t unpack_int64(const char *buf);\n",
" cdef uint64_t unpack_uint64(const char *buf);\n",
" cdef float unpack_float(const char *buf);\n",
" cdef double unpack_double(const char *buf);\n",
"\n",
"\n",
"cdef enum ArrayBuilderType:\n",
" CStringBuilderType = 1\n",
" CInt32BuilderType = 2\n",
" CDoubleBuilderType = 3\n",
" CFloatBuilderType = 4\n",
" CTimestampBuilderType = 5\n",
"\n",
"\n",
"cdef class Pg2Arrow:\n",
" cdef vector[shared_ptr[CArrayBuilder]] c_builders\n",
" cdef vector[ArrayBuilderType] c_types\n",
"\n",
" def __cinit__(self, types):\n",
" cdef CMemoryPool* pool = c_default_memory_pool()\n",
" cdef shared_ptr[CDataType] typ\n",
" for t in types:\n",
" if t == 'string':\n",
" self.c_builders.push_back(shared_ptr[CArrayBuilder](new CStringBuilder(pool)))\n",
" self.c_types.push_back(CStringBuilderType)\n",
" elif t == 'int32':\n",
" self.c_builders.push_back(shared_ptr[CArrayBuilder](new CInt32Builder(pool)))\n",
" self.c_types.push_back(CInt32BuilderType)\n",
" elif t == 'float64':\n",
" self.c_builders.push_back(shared_ptr[CArrayBuilder](new CDoubleBuilder(pool)))\n",
" self.c_types.push_back(CDoubleBuilderType)\n",
" elif t == 'float32':\n",
" self.c_builders.push_back(shared_ptr[CArrayBuilder](new CFloatBuilder(pool)))\n",
" self.c_types.push_back(CFloatBuilderType)\n",
" elif t == 'timestamp':\n",
" typ = shared_ptr[CDataType](new CTimestampType(TimeUnit_MICRO))\n",
" self.c_builders.push_back(shared_ptr[CArrayBuilder](new CTimestampBuilder(typ, pool)))\n",
" self.c_types.push_back(CTimestampBuilderType)\n",
" else:\n",
" self.c_builders.push_back(shared_ptr[CArrayBuilder](new CStringBuilder(pool)))\n",
" self.c_types.push_back(CStringBuilderType)\n",
"\n",
" @cython.boundscheck(False)\n",
" def process(self, char[:] buffer):\n",
" cdef ArrayBuilderType ftyp\n",
" cdef int16_t fnum\n",
" cdef int32_t flen\n",
" while buffer.size > 0:\n",
" fnum = unpack_int16(&buffer[0])\n",
" buffer = buffer[2:]\n",
" if fnum == -1:\n",
" break\n",
"\n",
" for i in range(self.c_builders.size()):\n",
" ftyp = self.c_types[i]\n",
" flen = unpack_int32(&buffer[0])\n",
" buffer = buffer[4:]\n",
"\n",
" if flen == -1:\n",
" self.c_builders[i].get().AppendNull()\n",
" else:\n",
" if ftyp == CStringBuilderType:\n",
" (<CStringBuilder*>self.c_builders[i].get()).Append(&buffer[0], flen)\n",
" elif ftyp == CInt32BuilderType:\n",
" (<CInt32Builder*>self.c_builders[i].get()).Append(unpack_int32(&buffer[0]))\n",
" elif ftyp == CDoubleBuilderType:\n",
" (<CDoubleBuilder*>self.c_builders[i].get()).Append(unpack_double(&buffer[0]))\n",
" elif ftyp == CFloatBuilderType:\n",
" (<CFloatBuilder*>self.c_builders[i].get()).Append(unpack_float(&buffer[0]))\n",
" elif ftyp == CTimestampBuilderType:\n",
" (<CTimestampBuilder*>self.c_builders[i].get()).Append(unpack_int64(&buffer[0]) + <int64_t>946684800000000)\n",
" buffer = buffer[flen:]\n",
"\n",
" arrays = []\n",
" cdef shared_ptr[CArray] array\n",
" for i in range(self.c_builders.size()):\n",
" self.c_builders[i].get().Finish(&array)\n",
" arrays.append(pyarrow_wrap_array(array))\n",
"\n",
" return arrays "
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "c92993a0-f873-441b-8106-e0b453fc3b75",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": 10,
"id": "bf5a272c-af8c-480c-bfe7-dae4c043d422",
"metadata": {},
"outputs": [],
"source": [
"async def copy(table):\n",
" buffers = []\n",
" async def sink(buffer):\n",
" buffers.append(buffer)\n",
"\n",
" await conn.copy_from_table(table, output=sink, format='binary')\n",
" return buffers"
]
},
{
"cell_type": "code",
"execution_count": 11,
"id": "fb8afcf0-66b0-4cad-bc38-93882003602b",
"metadata": {},
"outputs": [],
"source": [
"async def copy_to_arrow(sql_table, types):\n",
" schema = pa.schema(types.map(lambda x: _type_map.get(x, pa.string())).to_dict())\n",
" builder_types = types.map(lambda x: _builder_map.get(x, 'string')).to_list()\n",
" _sink = Pg2Arrow(builder_types)\n",
" \n",
" tables = []\n",
" skip_header = True\n",
" async def sink(buffer):\n",
" nonlocal skip_header\n",
" if skip_header:\n",
" buffer = buffer[19:]\n",
" skip_header = False\n",
" tbl = pa.table(_sink.process(buffer), schema=schema)\n",
" tables.append(tbl)\n",
"\n",
" await conn.copy_from_table(sql_table, output=sink, format='binary')\n",
" return pa.concat_tables(tables)"
]
},
{
"cell_type": "code",
"execution_count": 12,
"id": "c075cbc8-fdc9-4ffa-b33d-04abf4e0451a",
"metadata": {},
"outputs": [],
"source": [
"import asyncio\n",
"\n",
"async def test(coro, times=30, cooldown=10):\n",
" timings = []\n",
" for i in range(times):\n",
" await asyncio.sleep(cooldown)\n",
" t = pd.to_datetime('now')\n",
" z = await coro()\n",
" timings.append(pd.to_datetime('now') - t)\n",
" return z, timings"
]
},
{
"cell_type": "code",
"execution_count": 13,
"id": "68bf6a48-88c4-4a37-815b-7411138abbde",
"metadata": {},
"outputs": [],
"source": [
"tests = {\n",
" 'copy': lambda: copy(tbl),\n",
" 'fetch': lambda: conn.fetch(f'select * from {tbl}'),\n",
" 'get_pandas': lambda: get_pandas(f'select * from {tbl}'),\n",
" 'copy_to_arrow': lambda: copy_to_arrow(tbl, types)\n",
"}"
]
},
{
"cell_type": "code",
"execution_count": 14,
"id": "6184e0eb-1cd9-478f-ac9c-d5c21b0276ac",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"testing copy\n",
"testing fetch\n",
"testing get_pandas\n",
"testing copy_to_arrow\n"
]
}
],
"source": [
"results = {}\n",
"timings = {}\n",
"for name, t in tests.items():\n",
" print('testing', name)\n",
" results[name], timings[name] = await test(t)"
]
},
{
"cell_type": "code",
"execution_count": 15,
"id": "3a846c49-5807-4e89-a432-2c35221d5d71",
"metadata": {},
"outputs": [],
"source": [
"timings = pd.DataFrame(timings).apply(lambda x: x.dt.total_seconds())"
]
},
{
"cell_type": "code",
"execution_count": 16,
"id": "3dc0b927-1904-4d61-890a-985379d267cc",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"<AxesSubplot:>"
]
},
"execution_count": 16,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"image/png": "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\n",
"text/plain": [
"<Figure size 432x288 with 1 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"import seaborn as sns\n",
"sns.violinplot(data=timings)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "99dad90e-a716-4b2b-a1fa-76611bcb7b22",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": 17,
"id": "942ffcf8-5cd6-4b11-b5b2-6c68eec3621c",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"276.774221"
]
},
"execution_count": 17,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"sum(len(q) for q in results[\"copy\"]) / 1e6"
]
},
{
"cell_type": "code",
"execution_count": 18,
"id": "cd69e589-47a4-4c7e-8cf4-00134e0a3981",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"4.13 s ± 3.26 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
"30.7 ms ± 878 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n"
]
}
],
"source": [
"# for reference\n",
"%timeit pd.DataFrame.from_records(results[\"fetch\"], columns=list(results[\"fetch\"][0].keys()))\n",
"%timeit results[\"copy_to_arrow\"].to_pandas()"
]
},
{
"cell_type": "code",
"execution_count": 19,
"id": "7768dcca-6934-4637-8070-df517edae750",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>timestamp</th>\n",
" <th>symbol</th>\n",
" <th>open_price</th>\n",
" <th>high_price</th>\n",
" <th>low_price</th>\n",
" <th>close_price</th>\n",
" <th>volume</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>2000-01-01</td>\n",
" <td>0</td>\n",
" <td>-0.835820</td>\n",
" <td>-0.746893</td>\n",
" <td>0.294243</td>\n",
" <td>0.332640</td>\n",
" <td>832154</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>2000-01-01</td>\n",
" <td>1</td>\n",
" <td>0.893081</td>\n",
" <td>0.985754</td>\n",
" <td>1.159500</td>\n",
" <td>-1.943980</td>\n",
" <td>650086</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>2000-01-01</td>\n",
" <td>2</td>\n",
" <td>0.800148</td>\n",
" <td>0.253886</td>\n",
" <td>-1.370295</td>\n",
" <td>-1.400043</td>\n",
" <td>685743</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>2000-01-01</td>\n",
" <td>3</td>\n",
" <td>-1.261819</td>\n",
" <td>-0.128649</td>\n",
" <td>1.117490</td>\n",
" <td>-0.258251</td>\n",
" <td>659479</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>2000-01-01</td>\n",
" <td>4</td>\n",
" <td>-1.649070</td>\n",
" <td>0.551472</td>\n",
" <td>1.702268</td>\n",
" <td>-0.966815</td>\n",
" <td>584522</td>\n",
" </tr>\n",
" <tr>\n",
" <th>...</th>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4464095</th>\n",
" <td>2000-02-01</td>\n",
" <td>95</td>\n",
" <td>0.357868</td>\n",
" <td>-1.557160</td>\n",
" <td>-0.242268</td>\n",
" <td>1.096502</td>\n",
" <td>836040</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4464096</th>\n",
" <td>2000-02-01</td>\n",
" <td>96</td>\n",
" <td>0.844888</td>\n",
" <td>0.779728</td>\n",
" <td>0.611882</td>\n",
" <td>-0.089665</td>\n",
" <td>713316</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4464097</th>\n",
" <td>2000-02-01</td>\n",
" <td>97</td>\n",
" <td>-2.449516</td>\n",
" <td>0.784922</td>\n",
" <td>0.302922</td>\n",
" <td>1.179399</td>\n",
" <td>782881</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4464098</th>\n",
" <td>2000-02-01</td>\n",
" <td>98</td>\n",
" <td>-0.546269</td>\n",
" <td>-0.023306</td>\n",
" <td>0.107929</td>\n",
" <td>-0.947063</td>\n",
" <td>461618</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4464099</th>\n",
" <td>2000-02-01</td>\n",
" <td>99</td>\n",
" <td>-1.737921</td>\n",
" <td>0.297596</td>\n",
" <td>-1.050883</td>\n",
" <td>0.137020</td>\n",
" <td>774423</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"<p>4464100 rows × 7 columns</p>\n",
"</div>"
],
"text/plain": [
" timestamp symbol open_price high_price low_price close_price \\\n",
"0 2000-01-01 0 -0.835820 -0.746893 0.294243 0.332640 \n",
"1 2000-01-01 1 0.893081 0.985754 1.159500 -1.943980 \n",
"2 2000-01-01 2 0.800148 0.253886 -1.370295 -1.400043 \n",
"3 2000-01-01 3 -1.261819 -0.128649 1.117490 -0.258251 \n",
"4 2000-01-01 4 -1.649070 0.551472 1.702268 -0.966815 \n",
"... ... ... ... ... ... ... \n",
"4464095 2000-02-01 95 0.357868 -1.557160 -0.242268 1.096502 \n",
"4464096 2000-02-01 96 0.844888 0.779728 0.611882 -0.089665 \n",
"4464097 2000-02-01 97 -2.449516 0.784922 0.302922 1.179399 \n",
"4464098 2000-02-01 98 -0.546269 -0.023306 0.107929 -0.947063 \n",
"4464099 2000-02-01 99 -1.737921 0.297596 -1.050883 0.137020 \n",
"\n",
" volume \n",
"0 832154 \n",
"1 650086 \n",
"2 685743 \n",
"3 659479 \n",
"4 584522 \n",
"... ... \n",
"4464095 836040 \n",
"4464096 713316 \n",
"4464097 782881 \n",
"4464098 461618 \n",
"4464099 774423 \n",
"\n",
"[4464100 rows x 7 columns]"
]
},
"execution_count": 19,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"results[\"copy_to_arrow\"].to_pandas()"
]
},
{
"cell_type": "code",
"execution_count": 20,
"id": "71ef11ef-f1b4-4893-8b70-f346aaae9859",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>timestamp</th>\n",
" <th>symbol</th>\n",
" <th>open_price</th>\n",
" <th>high_price</th>\n",
" <th>low_price</th>\n",
" <th>close_price</th>\n",
" <th>volume</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>2000-01-01</td>\n",
" <td>0</td>\n",
" <td>-0.835820</td>\n",
" <td>-0.746893</td>\n",
" <td>0.294243</td>\n",
" <td>0.332640</td>\n",
" <td>832154</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>2000-01-01</td>\n",
" <td>1</td>\n",
" <td>0.893081</td>\n",
" <td>0.985754</td>\n",
" <td>1.159500</td>\n",
" <td>-1.943980</td>\n",
" <td>650086</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>2000-01-01</td>\n",
" <td>2</td>\n",
" <td>0.800148</td>\n",
" <td>0.253886</td>\n",
" <td>-1.370295</td>\n",
" <td>-1.400043</td>\n",
" <td>685743</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>2000-01-01</td>\n",
" <td>3</td>\n",
" <td>-1.261819</td>\n",
" <td>-0.128649</td>\n",
" <td>1.117490</td>\n",
" <td>-0.258251</td>\n",
" <td>659479</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>2000-01-01</td>\n",
" <td>4</td>\n",
" <td>-1.649070</td>\n",
" <td>0.551472</td>\n",
" <td>1.702268</td>\n",
" <td>-0.966815</td>\n",
" <td>584522</td>\n",
" </tr>\n",
" <tr>\n",
" <th>...</th>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4464095</th>\n",
" <td>2000-02-01</td>\n",
" <td>95</td>\n",
" <td>0.357868</td>\n",
" <td>-1.557160</td>\n",
" <td>-0.242268</td>\n",
" <td>1.096502</td>\n",
" <td>836040</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4464096</th>\n",
" <td>2000-02-01</td>\n",
" <td>96</td>\n",
" <td>0.844888</td>\n",
" <td>0.779728</td>\n",
" <td>0.611882</td>\n",
" <td>-0.089665</td>\n",
" <td>713316</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4464097</th>\n",
" <td>2000-02-01</td>\n",
" <td>97</td>\n",
" <td>-2.449516</td>\n",
" <td>0.784922</td>\n",
" <td>0.302922</td>\n",
" <td>1.179399</td>\n",
" <td>782881</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4464098</th>\n",
" <td>2000-02-01</td>\n",
" <td>98</td>\n",
" <td>-0.546269</td>\n",
" <td>-0.023306</td>\n",
" <td>0.107929</td>\n",
" <td>-0.947063</td>\n",
" <td>461618</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4464099</th>\n",
" <td>2000-02-01</td>\n",
" <td>99</td>\n",
" <td>-1.737921</td>\n",
" <td>0.297596</td>\n",
" <td>-1.050883</td>\n",
" <td>0.137020</td>\n",
" <td>774423</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"<p>4464100 rows × 7 columns</p>\n",
"</div>"
],
"text/plain": [
" timestamp symbol open_price high_price low_price close_price \\\n",
"0 2000-01-01 0 -0.835820 -0.746893 0.294243 0.332640 \n",
"1 2000-01-01 1 0.893081 0.985754 1.159500 -1.943980 \n",
"2 2000-01-01 2 0.800148 0.253886 -1.370295 -1.400043 \n",
"3 2000-01-01 3 -1.261819 -0.128649 1.117490 -0.258251 \n",
"4 2000-01-01 4 -1.649070 0.551472 1.702268 -0.966815 \n",
"... ... ... ... ... ... ... \n",
"4464095 2000-02-01 95 0.357868 -1.557160 -0.242268 1.096502 \n",
"4464096 2000-02-01 96 0.844888 0.779728 0.611882 -0.089665 \n",
"4464097 2000-02-01 97 -2.449516 0.784922 0.302922 1.179399 \n",
"4464098 2000-02-01 98 -0.546269 -0.023306 0.107929 -0.947063 \n",
"4464099 2000-02-01 99 -1.737921 0.297596 -1.050883 0.137020 \n",
"\n",
" volume \n",
"0 832154 \n",
"1 650086 \n",
"2 685743 \n",
"3 659479 \n",
"4 584522 \n",
"... ... \n",
"4464095 836040 \n",
"4464096 713316 \n",
"4464097 782881 \n",
"4464098 461618 \n",
"4464099 774423 \n",
"\n",
"[4464100 rows x 7 columns]"
]
},
"execution_count": 20,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"results[\"get_pandas\"]"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "bc9bcecd-d643-4561-a6ce-0ed2c482f239",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": 21,
"id": "34078e6f-f76c-4d77-a5b6-f6fb33663bb8",
"metadata": {},
"outputs": [],
"source": [
"# import numpy as np\n",
"\n",
"# r = \"\"\"\n",
"# DROP TABLE IF EXISTS minute_bars\n",
"# \"\"\"\n",
"\n",
"# await conn.execute(r)\n",
"\n",
"# r = \"\"\"\n",
"# CREATE TABLE minute_bars\n",
"# (\n",
"# timestamp timestamp without time zone,\n",
"# symbol integer,\n",
"# open_price real,\n",
"# high_price real,\n",
"# low_price real,\n",
"# close_price real,\n",
"# volume integer\n",
"# )\n",
"# \"\"\"\n",
"\n",
"# await conn.execute(r)\n",
"\n",
"# times = pd.date_range('2000', '2000-02-01', freq='1min')\n",
"# symbols = list(range(100))\n",
"\n",
"# records = [\n",
"# (t, s, *np.random.randn(4).tolist(), np.random.randint(0, 1_000_000))\n",
"# for t in times\n",
"# for s in symbols\n",
"# ]\n",
"\n",
"# await conn.copy_records_to_table('minute_bars', records=records)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.0"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment