Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1krNe5-0003TQ-3X for psycopg@arkaria.postgresql.org; Mon, 21 Dec 2020 16:02:49 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.92) (envelope-from ) id 1krNe2-0003JV-HM for psycopg@arkaria.postgresql.org; Mon, 21 Dec 2020 16:02:46 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1krNe1-0003JO-68 for psycopg@lists.postgresql.org; Mon, 21 Dec 2020 16:02:46 +0000 Received: from out5-smtp.messagingengine.com ([66.111.4.29]) by magus.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1krNdu-0000Dx-H2 for psycopg@postgresql.org; Mon, 21 Dec 2020 16:02:44 +0000 Received: from compute2.internal (compute2.nyi.internal [10.202.2.42]) by mailout.nyi.internal (Postfix) with ESMTP id 0D69C5C01E1; Mon, 21 Dec 2020 11:02:36 -0500 (EST) Received: from mailfrontend2 ([10.202.2.163]) by compute2.internal (MEProxy); Mon, 21 Dec 2020 11:02:36 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=aklaver.com; h= subject:to:references:from:message-id:date:mime-version :in-reply-to:content-type:content-transfer-encoding; s=fm1; bh=x 0loPR9EfvBoKGv1VVXrGFExGut9KmMlWOvpomRiUfo=; b=U3SisHfCRowWVnZ4a CoMZf3vM+L8OiPQO9RMFR66fBxGHGeeT8B4mBEyjIW5hV+vdZER4aU0g4Yet2Aw6 RUrqNerRMW9ct8AiGwueEtFH1n7AImkT/WA1c/70FkDybOLHbwZdO4qwEapf0QMV TXPglIMVFClyg3hdOW3YmND6OamMaT82XXrzDZSysHKYxIfLuYWa0c+x3vDwqjRZ grzJw77X9C3ATN8xTcAhSV2IUDXcmcA8+9108K5zCNshv/ULG2J+Ku1IXr9gqVuZ bqHQOtwwTBcZqfnTob47Ja8koHG4nNsFGAYhDtiu8nQdcxC4WaflB7hW708ZkMz+ /W0fA== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=content-transfer-encoding:content-type :date:from:in-reply-to:message-id:mime-version:references :subject:to:x-me-proxy:x-me-proxy:x-me-sender:x-me-sender :x-sasl-enc; s=fm1; bh=x0loPR9EfvBoKGv1VVXrGFExGut9KmMlWOvpomRiU fo=; b=FjmEAyqmT6GmfgIM8OTdCG1xkIPLiUZDrTAFrx59WCWPOQ2ra5Xa/crEH CUQexaeo4KqQw1gpUl/mOSvEvK5naOHvdqbAzmJv9acVEXBvfsnoqa1QLeu16yOC T25PK3wJ7co+7kYHQ0IGSJYrgXZb4bJSudbU+Gb8wipImSl+taQ8nQ4lcBrYkfbB OgARLGby2FWhuCP7q4PBOTFQWuLQN9jaWnH5D47nbPd7MH/4yOKdtWBzNUBQjjnz FhM7glmCd9QouWybb/B4CLKkRA8DU1efqKSS/lZoRaKaQ05syAfvFQXxTA043+mc mNljDguCOZ6UknQ6JiEeFzfDqiJNQ== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedujedrvddtvddgkeejucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepuffvfhfhkffffgggjggtgfesthejredttdefjeenucfhrhhomheptegurhhi rghnucfmlhgrvhgvrhcuoegrughrihgrnhdrkhhlrghvvghrsegrkhhlrghvvghrrdgtoh hmqeenucggtffrrghtthgvrhhnpeetkeehjefhjefgvddvveejvdetffehteetgefggfeh teeujeefvedugffhkefgheenucffohhmrghinhepphhoshhtghhrvghsqhhlrdhorhhgpd hgihhthhhusgdrtghomhenucfkphepjeehrddujedvrddugedrudejnecuvehluhhsthgv rhfuihiivgeptdenucfrrghrrghmpehmrghilhhfrhhomheprggurhhirghnrdhklhgrvh gvrhesrghklhgrvhgvrhdrtghomh X-ME-Proxy: Received: from [192.168.1.4] (75-172-14-17.tukw.qwest.net [75.172.14.17]) by mail.messagingengine.com (Postfix) with ESMTPA id DC6FB108005B; Mon, 21 Dec 2020 11:02:29 -0500 (EST) Subject: Re: psycopg3, prepared statements To: Daniele Varrazzo , psycopg@postgresql.org References: From: Adrian Klaver Message-ID: <25a137a0-9ad3-bb9f-b008-263dcc81a645@aklaver.com> Date: Mon, 21 Dec 2020 08:02:29 -0800 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Thunderbird/78.6.0 MIME-Version: 1.0 In-Reply-To: Content-Type: text/plain; charset=utf-8; format=flowed Content-Language: en-US Content-Transfer-Encoding: 7bit List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Precedence: bulk On 12/21/20 6:24 AM, Daniele Varrazzo wrote: > The one thing, the most requested thing in psycopg, is support for > prepared statements. > > In psycopg3 for the moment there is: > > - very low level support for prepared statement, i.e. wrapping of > libpq functions such as PQsendPrepare/PQsendQueryPrepared > (https://www.postgresql.org/docs/current/libpq-async.html#LIBPQ-PQSENDPREPARE) > - automatic use of prepared statements in `cursor.executemany()`, > which might eventually stop sucking. > > Gathering some ideas: > > Prepared statements in the server are per session, so any form of > cache is better connected to the connection than the cursor, although > the cursors are the obvious interface to give commands. > > In the past [1] I thought about exposing explicit prepare/deallocate > on the cursor, and it was a single prepared query per cursor. A > `cursor.prepare(query)` with no args doesn't have types information > though: if any it should take an optional array of parameters to get > types from. > > What I'm thinking about is to prepare queries automatically with a schema such: > > - decisions are made after the query is transformed to postgres format > (i.e. it is reduced to bytes, all the client-side manipulations have > been done, placeholders have been transformed to $ format). There is > an object in psycopg3 that takes care of this transformation [2] > - the number of times a query is seen is stored in a LRU cache on the connection > - if a query is seen more than `connection.prepare_threshold` times > (proposed default: 5) then it is prepared with the name > f'pg3_{hash(query)}' and the following executions are prepared. > - if more than `connection.prepared_number` queries are prepared, the > one used least recently is deallocated and evicted from the cache > (proposed default: 100). > - Parameters may be fudged on the connection: prepared_threshold=0 > would prepare all queries, prepared_threshold=None would disable > preparing. > - For the control freak, cursor.execute(query, params, prepare=True) > would prepare the query immediately, if it isn't already, > prepare=False would avoid preparation. The default None would enable > the automatic choice. So your plan from [1] was like that in plpythonu where the process is broken down into two parts. What I'm not following is whether that is still the plan or whether prepare/execute is going to happen without the cursor.prepare() and just be automatic on cursor.execute()? With the provision to override per cursor. > > [1] https://gist.github.com/dvarrazzo/3797445 > [2] https://github.com/psycopg/psycopg3/blob/c790a832/psycopg3/psycopg3/_queries.py#L27 > > What do you think? > > Cheers > > -- Daniele > > -- Adrian Klaver adrian.klaver@aklaver.com