The physical storage for rows is described in the docs in Database Page Layout. The column contents for the same row are all stored in the same disk page, with the notable exception of TOAST'ed contents (too large to fit in a page). Contents are extracted sequentially within each row, as explained:
To read the data you need to examine each attribute in turn. First
check whether the field is NULL according to the null bitmap. If it
is, go to the next. Then make sure you have the right alignment. If
the field is a fixed width field, then all the bytes are simply
placed.
In the simplest case (no TOAST'ed columns), postgres will fetch the entire row even if few columns are needed. So in this case, the answer is yes, having more columns may have a clear adverse impact on waster buffer cache, particularly if the column contents are large while still under the TOAST threshold.
Now the TOAST case: when an individual field exceeds ~2kB , the engine stores the field contents into a separate physical table. It also comes into play when the entire row doesn't fit into a page (8kB by default): some of the fields are moved to TOAST storage. Doc says:
If it's a variable length field (attlen = -1) then it's a bit
more complicated. All variable-length data types share the common
header structure struct varlena, which includes the total length of
the stored value and some flag bits. Depending on the flags, the data
can be either inline or in a TOAST table; it might be compressed, too
TOAST'ed contents are not fetched when they're not explicitly needed, so their effect on the total number of pages to fetch is small (a few bytes per column). This explains the results in @dezso's answer.
As for writes, each row with all its columns is entirely rewritten on each UPDATE, no matter what columns are changed. So having more columns is obviously more costly for writes.
The first thing to look at is your indexing strategy. Bad execution plans are often caused by insufficient indexes or stale statistics. Your statistics warning might hint at that.
If that does not resolve your problem there are a few hacks that you can try:
A top operation requires SQL Server to separate query sections in the execution plan.
If you know you are always dealing with less then 2 billion rows you could write your query like this:
SELECT * FROM(
SELECT TOP(2000000000) *
FROM <complex join>
WHERE ro.reportguid = '64c0a4af-ee4d-4e83-a194-2a14e8a6ab0e'
)X
WHERE l.geom.STGeometryType() = 'Point'
An alternative is to write a scalar valued function that takes in the l.geom column and a few other columns from the other tables and returns the STGeometryType() value while ignoring all the other values. Because SQL Server does not consider the function logic at optimization time, it is forced to execute the function after the join. That does not guarantee that the other filter is executed first but often it works out that way.
The third option is to play around with join hints and join order. They often lead to a change in where filters are applied.
All three options I would consider a last resort because they make the code ugly and you run the risk that someone removes that ugliness later trying to make the code better.
Best Answer
Both do the same and you won't be able to measure any difference in performance.
Details
This is a string literal or string constant:
'5'
The manual:
If there is no context from which a type can be derived, a string literal is initially assumed to be type
text
. (Not the case in your example.)The manual once more:
This is a numeric literal or numeric constant:
5
The manual:
So a numeric literal starts out with a specific type. It may then be cast to a different type as the context requires - if such a cast is defined. That's a subtle, but important difference - which makes no effective difference in your case, since
5
is initiallyinteger
, which is exactly the type it needs to be.But it matters in other cases. Try this:
Because the numeric literal starts out as
integer
and there is no assignment cast defined forinteger
-->text
. (Any type can be cast totext
with an explicit cast (0::text
) but that cast is not assumed here.)