I have a big query statement (about 120 lines and access over 10 tables and using CTE). I created a Connection pool with default value config and using directly fetch method of Pool object. However, It take over 30 seconds to executed (sometimes over 1 minutes). But, when I tried to execute this query by SQLClient IDE and psycopg2, everything was OK (execution time was only some miliseconds). I sure this problem didn't come from the query perfomance
_pool = await asyncpg.create_pool(host=config.ERP_DB_HOST,
port=config.ERP_DB_PORT,
database=config.ERP_DB_NAME,
user=config.ERP_DB_USER,
password=config.ERP_DB_PASSWORD,
max_size=int(config.ERP_DB_MAXCONN))
rows = await _pool.fetch(sql)
Please provide more information: your schema and the query you are running.
Also, the abnormality possibly hints at a bad plan being generated for the cached prepared statement. Try this:
async with pool.acquire() as conn:
stmt = await conn.prepare(sql)
rows = await stmt.fetch()
Also, the abnormality possibly hints at a bad plan being generated for the cached prepared statement. Try this:
async with pool.acquire() as conn: stmt = await conn.prepare(sql) rows = await stmt.fetch()
I tried it, but still not effective :(
This is my query sql_statement.txt
I will draw schema asap.
One more stupid question: I think query planning is server-side. Why connector library can interfere with that process and generated bad plan for this query? :(
Why connector library can interfere with that process and generated bad plan for this query?
Because asyncpg uses prepared statements by default and other drivers usually do not. The use of prepared statements generally improves performance, but in certain cases the chosen generic plan might be very inefficient for a particular set of arguments. This is especially likely if the distribution of data in the tables is extremely uneven.
I tried it, but still not effective :(
Weird. Can you try substituting query arguments with constant values in the text of the query?
I tried to modify my query without CTE and add parameter statement_cache_size=0 when init pool. It's worked.
I think some bad plans was cached from this :-?
I'm surprised that the workaround with an explicit prepared statement didn't work for you. When you do connection.prepare(sql) you avoid the use of the shared statement cache and guarantee that there will be a freshly built plan for your query. statement_cache_size=0 achieves the same result only for all queries.