Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1ttVWU-00DIl8-1e for pgsql-general@arkaria.postgresql.org; Sat, 15 Mar 2025 17:42:10 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.94.2) (envelope-from ) id 1ttVWS-0009uV-MS for pgsql-general@arkaria.postgresql.org; Sat, 15 Mar 2025 17:42:08 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1ttVWS-0009qa-81 for pgsql-general@lists.postgresql.org; Sat, 15 Mar 2025 17:42:08 +0000 Received: from mail-ed1-x52e.google.com ([2a00:1450:4864:20::52e]) by magus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.96) (envelope-from ) id 1ttVWO-003302-2N for pgsql-general@postgresql.org; Sat, 15 Mar 2025 17:42:07 +0000 Received: by mail-ed1-x52e.google.com with SMTP id 4fb4d7f45d1cf-5e61da95244so5469624a12.2 for ; Sat, 15 Mar 2025 10:42:05 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1742060524; x=1742665324; darn=postgresql.org; h=to:subject:message-id:date:from:mime-version:from:to:cc:subject :date:message-id:reply-to; bh=g3R7AwKgeK6f3Z6lwUraIv4Foc5SBb3fsU/cEdMhKAM=; b=ANF0hNu7Rl9nMepWQ5ZLOgRriDDdf0ra2EvFzdU5EcaClu8GCuMRcIsyl4il91bcWg NJ/KcSlMkpeT8IHrCgWGoZFGak66Tz0JypdXB6yxPlXS4GioQRoa6/+ufao9H3q23Vsi gCUIOrlncUPMETsl9psBd7ldRPHJZd4gp0gNkF+0AD54F/QdN9z2xU1ZM2SWar1tYXKL nMtd9+hJHf6RUlq9A90rX+AlAJ3X7wAt87a/Q5F1Az6/+5Ov3gsPHxkU49eobgEhz9/U fYcpMxpkw7BP6thA6AlcTbJbJyvyyMa2Kb7tf57SRvsS1xlfZxn85gSDoCs0ZjWDB6iX Nx0Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1742060524; x=1742665324; h=to:subject:message-id:date:from:mime-version:x-gm-message-state :from:to:cc:subject:date:message-id:reply-to; bh=g3R7AwKgeK6f3Z6lwUraIv4Foc5SBb3fsU/cEdMhKAM=; b=rS5wl2m3eq9dKX0EXlvO5EX/YlD2PKhhjaAIwIutkL7UDbk4Lf7W1PEwyNEuSiEQUP B/jonmqbsJLnURhimgmedRZd6mQkGMQi/90H/rqQQTykDkQeANAiFBPaAdCQJsSYGM8I BERyDiraLuE7WLoa3ZQrv+cBd2VZqw6CTxmIW6feznDlrMgvLOtkx3Biy+wQn8AD1cdl jrv3sCv2Q9+tHVR6yjMh5UiAz4UFdDxB9hao4gkete+M6/GE0rZqV3e/NfSerHz2E+Fd Sqbp4ZdTkW3J2F72b1PTYnvyStDtWPMksjVUsNtuQZ2p7mdt0ijVyo1Y9UN+XCf2icWE xy3A== X-Gm-Message-State: AOJu0Yx5djeBC9Kq6/6sa5LGg2JZR4x4eS88eHd3NGCzWlD2D+P4Sx91 SblT4w9am5SPEYG3L63yLmRclPzXBFtsTpq5oIwex7R8+uphmvQeN+pfFyt3cTJep7YUs7nzChq 4pzb7XQrBA6gQDSzptVBiqFLqUBaao9im X-Gm-Gg: ASbGncvV1fh/t2RvN4OrvcESxV2iHq4/wmWwLQXgvkTaCmhTD9karkXWyK5aqgiQRcQ rQ4qlbwuUPgO+lSrnzg6G5Fuvdo1kr4YTcst42duR3DhLWb/OR+0l0+eMKo0qajX+ee6yaKmH33 gqfjeQwbyF182apIC8YMjQ+R8DOs4= X-Google-Smtp-Source: AGHT+IGKWMhV8n1t8dw6CgNTibzzjxXibfk/kxxzauqlMOzQ++8XHXWxq7DJsAU4sKhGcjj3QPoreRKKh6pJ6YymZG4= X-Received: by 2002:a17:907:9281:b0:abf:49de:36de with SMTP id a640c23a62f3a-ac330108ae9mr875592766b.1.1742060524246; Sat, 15 Mar 2025 10:42:04 -0700 (PDT) MIME-Version: 1.0 From: Justin Blank Date: Sat, 15 Mar 2025 17:41:53 +0000 X-Gm-Features: AQ5f1JoUb2HhMpPCezXK7SjTOs1TTTPi-VPLwFqSgHJWjUgSlJsJMBrSdQPzGBQ Message-ID: Subject: The logic behind comparing generic vs. custom plan costs To: pgsql-general@postgresql.org Content-Type: text/plain; charset="UTF-8" List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk I've been looking into the way that postgres decides whether to use a custom or generic plan. I believe I understand how, but I have confused myself about the why. In plancache.c, the code always executes a custom plan for the first five iterations, and afterwards, it compares the average cost of the custom plan (including the planning cost) to the cost of a generic plan (not including planning), and choose the option with the lower cost. My idea had been that even if the custom plans average higher cost than the generic plan, it is still worth considering custom plans. If 1 time in 5, the custom plan is 10% of the cost of the generic plan, it doesn't matter if the average custom plan is worse, you should at least determine the cost of the custom plan before deciding whether to use it or the generic plan. Even if 80% of the time, you don't use the custom plan, the payoff in the good case may be worth it. However, after starting to implement that idea, I became confused, and the underlying logic of comparing custom and generic plans stopped making sense to me. I can think of two different reasons the cost estimates for the generic plan and custom plan can differ: 1. The two plans substantively differ: they use a different join order, different join strategy, or different indexes. 2. They do not fundamentally differ, but the custom plan makes different estimates of the selectivity of predicates because it knows their precise values. For the sake of deciding between custom and generic plans, it seems like only the first type of difference matters. So my first question is whether there's any value in comparing the cost estimates for custom plans that have the same access plan as the generic plan. Continuing to cases where the plans differ meaningfully, I'm not sure that comparison makes sense either. If the custom plan beats the generic plan, it seems reasonable to take that as a real improvement. However, if the custom plan has a higher cost than the generic plan, this may or may not count against the custom plan. The planner used the bind parameters of the specific query. So it may be that the custom plan really is worse (the planner has made a mistake) but it may also be that it considered the access plan of the generic plan, and it was worse for those particular bind parameters. In this case, the custom plan appears worse than the generic plan, but would ideally be preferred. Does my reasoning make sense? Or have I misunderstood something about this process and how to reason about these cost estimates? I'm very unsure, and worrying I've completely misunderstood, as if I'm right, the logic in plancache.c doesn't make much sense. Justin Blank