Egor Rogov
PostgreSQL 14
Internals
 
 
            
           
PostgreSQL 14 Internals
  
     
  
 
       
Contents at a Glance


    



     
   

    
      



   
   


     
    
    

    
    


  


    








Table of Contents
   
 
 








    
      
    
 

        

     
     
     
    

     



      
  
   
 





 
 





 

   
 


 
 
    

      
   
    
   
     
 
 
      

     
  
   
 
    






     
    
      
      
   


  
 

  
 
    
      

   
    
    
    
 

      
    

      
   
  

    
    
    



      
  

 
 
 
    
 
      


   
 
 


 
 
   
 
  
   

   
 
  




 



   
   


     
   

   

    


  



 

    
     
   
 
    
 
  
 

     
 
 
 



 
    
    

    




    


   

  
 
 
 
 

      
    
 

  
   
   
    
   
    
     
   
    
    



    

    
    
  
   
    
    
     


    
   
  
  
   
    

    
    

     

  


   

    
      
   
     
 

  
   

   


  




     
    
    

     
    




 



  

  

     
     
    
  
 

 

   
  
  
  
 
    

   




      
 
  
    

   
  
  

  
  
 
 


    
   

  

     
   
   


  
 
    





     
     





  
 
     



  

    

    

     


 
   
   
     
  
 



    

  
 
     
     

   

 
 
 

About This Book
         
  
      
    
             
               
          
             
            
             
     
              
            
              
      
     
            
           
            
             
      
             
             

  
               
          
       
              
            
         
               
    
           
              
             
            
   
            
            
            
         
          
             
 
              
          
              
             
   
            
          
           
              
      


         
             
              
         


              
                 
               
             
                
           
       
               
             
          
            
             
         
             
           4MB
           
          
              
        
            
            
           




  
            
             
    
               
          
            
          
=> SELECT now();
now
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
2023−03−06 14:00:08.008545+03
(1 row)
             
           
              
   
           
           
=> SHOW server_version;
server_version
−−−−−−−−−−−−−−−−
14.7
(1 row)
            
        
            
           

              



postgres$ whoami
postgres
          
     

             
  
             
     
             
              
             
      

             
            
             
    
             
             
             
 
             
             
             
      


  
              
          
              

1
Introduction
  

           
            
          
           
             
              
       
            
          
               
             
   
       
            
        
             
 



 
          
postgres template0 template1
CREATE DATABASE
newdb
PostgreSQL instance
database
cluster
 
            
             
             
              
            
    
            
             
        
            
           
  
              
           


  
              
              
              
              
                
             

          
     
            
      
          
   
         
        
          
   
           
    
             
               
          
           
    
  


 

         
         
            
              
   
            
            
       
           
           
       
postgres template1
pg_catalog public plugh pg_catalog public
pg_global
pg_default
xyzzy
common cluster objects

  
      
             
         
           
      
          
           
             
             

           
           
         
       

          
            
              
          
           
             
           
         
           
              
              
             
                
          

 
            
               
      
  
          
    
            
           
               
            
        
             
             
  
visibility map
free space map
the main fork
12345_vm
12345_fsm.1
12345_fsm
12345.2
12345.1
12345


  
           
             
        
            
             
              
      
              
          
             
     
              
 
=> CREATE UNLOGGED TABLE t(
a integer,
b numeric,
c text,
d json
);
=> INSERT INTO tVALUES (1, 2.0, 'foo', '{}');
=> SELECT pg_relation_filepath('t');
pg_relation_filepath
−−−−−−−−−−−−−−−−−−−−−−
base/16384/16385
(1 row)
          
               
 
=> SELECT oid FROM pg_database WHERE datname = 'internals';
oid
−−−−−−−
16384
(1 row)

 
=> SELECT relfilenode FROM pg_class WHERE relname = 't';
relfilenode
−−−−−−−−−−−−−
16385
(1 row)
        
=> SELECT size
FROM pg_stat_file('/usr/local/pgsql/data/base/16384/16385');
size
−−−−−−
8192
(1 row)
           
            
            
             
           
            
        
             
           
=> SELECT size
FROM pg_stat_file('/usr/local/pgsql/data/base/16384/16385_init');
size
−−−−−−
0
(1 row)
           
           
             
     




  
              
            
      
=> VACUUM t;
=> SELECT size
FROM pg_stat_file('/usr/local/pgsql/data/base/16384/16385_fsm');
size
−−−−−−−
24576
(1 row)
              
          
              
            
           
           
           
           
             
             
             
          
              
            
            
=> SELECT size
FROM pg_stat_file('/usr/local/pgsql/data/base/16384/16385_vm');
size
−−−−−−
8192
(1 row)
            


 

             
            
       
                 
           
               
        
               
               
             

               
         
   
           
            
                
         
           
              
               
     
           
               
           



  
              
               
         
=> SELECT attname, atttypid::regtype,
CASE attstorage
WHEN 'p' THEN 'plain'
WHEN 'e' THEN 'external'
WHEN 'm' THEN 'main'
WHEN 'x' THEN 'extended'
END AS storage
FROM pg_attribute
WHERE attrelid = 't'::regclass AND attnum > 0;
attname | atttypid | storage
−−−−−−−−−+−−−−−−−−−−+−−−−−−−−−−
a | integer | plain
b | numeric | main
c | text | extended
d | json | extended
(4 rows)
    
               
        
          

             
 
             
       
           
                 
             
            
              


 
            
           
          
               
            

                 
           

                
      
               
 
                
   
              
              
            
             
       
=> ALTER TABLE tALTER COLUMN dSET STORAGE external;
          
attname | atttypid | storage
−−−−−−−−−+−−−−−−−−−−+−−−−−−−−−−
a | integer | plain
b | numeric | main
c | text | extended
d | json | external
(4 rows)
            
           
      

  
            
          
    
=> SELECT relnamespace::regnamespace, relname
FROM pg_class
WHERE oid = (
SELECT reltoastrelid
FROM pg_class WHERE relname = 't'
);
relnamespace | relname
−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−
pg_toast | pg_toast_16385
(1 row)
=> \d+ pg_toast.pg_toast_16385
TOAST table "pg_toast.pg_toast_16385"
Column | Type | Storage
−−−−−−−−−−−−+−−−−−−−−−+−−−−−−−−−
chunk_id | oid | plain
chunk_seq | integer | plain
chunk_data | bytea | plain
Owning table: "public.t"
Indexes:
"pg_toast_16385_index" PRIMARY KEY, btree (chunk_id, chunk_seq)
Access method: heap
               
    
           
             
                
 
=> SELECT indexrelid::regclass FROM pg_index
WHERE indrelid = (
SELECT oid
FROM pg_class WHERE relname = 'pg_toast_16385'
);
indexrelid
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
pg_toast.pg_toast_16385_index
(1 row)

 
=> \d pg_toast.pg_toast_16385_index
Unlogged index "pg_toast.pg_toast_16385_index"
Column | Type | Key? | Definition
−−−−−−−−−−−+−−−−−−−−−+−−−−−−+−−−−−−−−−−−−
chunk_id | oid | yes | chunk_id
chunk_seq | integer | yes | chunk_seq
primary key, btree, for table "pg_toast.pg_toast_16385"
            
                
 
          
=> UPDATE tSET c = repeat('A',5000);
=> SELECT *FROM pg_toast.pg_toast_16385;
chunk_id | chunk_seq | chunk_data
−−−−−−−−−−+−−−−−−−−−−−+−−−−−−−−−−−−
(0 rows)
             
       
        
=> UPDATE tSET c=(
SELECT string_agg( chr(trunc(65+random()*26)::integer), '')
FROM generate_series(1,5000)
)
RETURNING left(c,10) || '...' || right(c,10);
?column?
−−−−−−−−−−−−−−−−−−−−−−−−−
YEYNNDTSZR...JPKYUGMLDX
(1 row)
UPDATE 1
           
=> SELECT chunk_id,
chunk_seq,
length(chunk_data),
left(encode(chunk_data,'escape')::text, 10) || '...' ||
right(encode(chunk_data,'escape')::text, 10)
FROM pg_toast.pg_toast_16385;

   
chunk_id | chunk_seq | length | ?column?
−−−−−−−−−−+−−−−−−−−−−−+−−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−−−
16390 | 0 | 1996 | YEYNNDTSZR...TXLNDZOXMY
16390 | 1 | 1996 | EWEACUJGZD...GDBWMUWTJY
16390 | 2 | 1008 | GSGDYSWTKF...JPKYUGMLDX
(3 rows)
              
              
             
         
              
               
               

               
         
          
              
             
        
              
            
  
   
       
            
            
            
                


 
              
           

            
             
              
           
         
              
       
           
     
        
       
   
      
       
      
      
             
          
         
              
             
          
         
    
            
               
              

     
              

             
         
           
             
backend
backend
postmaster
backend background processes
buffer cache
shared memory
PostgreSQL
instance
client
application
client
application
client
application
cache
operating
system
              
               
              
          
         
     
            
        
  

 
          
         
             
         
           
            
   
           
        
       
              
           
     
           
           
         
          
           
          
              

            
             
  
             
    
          
             
             




     
         
           
              
             
             

Part I
Isolation
and MVCC
2
Isolation
 
            
   
               
             
         
            
            
             
                
   
            
           
              
              
             
           
      
           
       
            
            

 
            
                
           
             
             
      
              
            
             
            
             

             
          
         
              
             
   
            
            
            
           

          
   
           
           
            
             
        
         
                

       
           
      
             
            
          
           
             
             
         
           
           
             
  
           
          
              
             
             
                 

       
            
           
           
            
               


 
          
            
      
             
            
 
 
             
             
            

             
            
           
             
            
       
         
  
         
   
             
           
           
            
    
         

       
    
          
           
            

           
             
             
           
            
               
        
           
 
    
            
          
          
             
      
           
            
              
            
            
           
             
  
          
   

 
   
            
               
            
          
           
           
          
   
           
      
lost dirty non-repeatable phantom other
update read read read anomalies
Read Uncommitted yes yes yes yes
Read Committed yes yes yes
Repeatable Read yes yes
Serializable
  
             
  
                
            
       
              
           
            
           
          
          

    
           
          
                 
          
                
            
          
                
         
            
             
              
      
              
           
          
             
              
    
    
          
            
            
           
  
             
           
          

 
         
            
             
            
         
             
             
              
          
              
     
lost dirty non-repeatable phantom other
updates reads reads reads anomalies
Read Committed yes yes yes yes
Repeatable Read yes
Serializable
            
      
               
       
=> CREATE TABLE accounts(
id integer PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY,
client text,
amount numeric
);
=> INSERT INTO accounts VALUES
(1, 'alice', 1000.00), (2, 'bob', 100.00), (3, 'bob', 900.00);
 
                
        


    
=> BEGIN;
=> SHOW transaction_isolation;
transaction_isolation
−−−−−−−−−−−−−−−−−−−−−−−
read committed
(1 row)
             
  
=> SHOW default_transaction_isolation;
default_transaction_isolation
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
read committed
(1 row)
           
               

=> UPDATE accounts SET amount = amount - 200 WHERE id = 1;
=> SELECT *FROM accounts WHERE client = 'alice';
id | client | amount
−−−−+−−−−−−−−+−−−−−−−−
1 | alice | 800.00
(1 row)
              
 
=> BEGIN;
=> SELECT *FROM accounts WHERE client = 'alice';
id | client | amount
−−−−+−−−−−−−−+−−−−−−−−−
1 | alice | 1000.00
(1 row)
         
  

 
           
      
=> COMMIT;
=> SELECT *FROM accounts WHERE client = 'alice';
id | client | amount
−−−−+−−−−−−−−+−−−−−−−−
1 | alice | 800.00
(1 row)
=> COMMIT;
              
            

            
             
              
  
IF (SELECT amount FROM accounts WHERE id = 1) >= 1000 THEN
UPDATE accounts SET amount = amount - 1000 WHERE id = 1;
END IF;
            
             
           
           
 
IF (SELECT amount FROM accounts WHERE id = 1) >= 1000 THEN
UPDATE accounts SET amount = amount - 200 WHERE id = 1;
COMMIT;
UPDATE accounts SET amount = amount - 1000 WHERE id = 1;
END IF;

    
             
              
               
     
         
     
              
 
ALTER TABLE accounts
ADD CHECK amount >= 0;
                
            
   
   
         
          
           
          
          
          
            
    
  
                
             
           
       

 
           
           
          
=> BEGIN;
=> UPDATE accounts SET amount = amount - 100 WHERE id = 2;
           
             
 
=> BEGIN;
=> SELECT amount FROM accounts WHERE id = 2;
amount
−−−−−−−−
100.00
(1 row)
      
=> UPDATE accounts SET amount = amount + 100 WHERE id = 3;
=> COMMIT;
             
 
=> SELECT amount FROM accounts WHERE id = 3;
amount
−−−−−−−−−
1000.00
(1 row)
=> COMMIT;
            
      
              
       
SELECT sum(amount) FROM accounts WHERE client = 'bob';

    
            
                 
        
                
               
       
=> SELECT amount, pg_sleep(2)
-- two seconds
FROM accounts WHERE client = 'bob';
           
  
=> BEGIN;
=> UPDATE accounts SET amount = amount + 100 WHERE id = 2;
=> UPDATE accounts SET amount = amount - 100 WHERE id = 3;
=> COMMIT;
               
          
amount | pg_sleep
−−−−−−−−−+−−−−−−−−−−
0.00 |
1000.00 |
(2 rows)
               
            
             
          
=> CREATE FUNCTION get_amount(id integer) RETURNS numeric
AS $$
SELECT amount FROM accounts a WHERE a.id = get_amount.id;
$$ VOLATILE LANGUAGE sql;
=> SELECT get_amount(id), pg_sleep(2)
FROM accounts WHERE client = 'bob';
           
   

 
=> BEGIN;
=> UPDATE accounts SET amount = amount + 100 WHERE id = 2;
=> UPDATE accounts SET amount = amount - 100 WHERE id = 3;
=> COMMIT;
            
get_amount | pg_sleep
−−−−−−−−−−−−+−−−−−−−−−−
100.00 |
800.00 |
(2 rows)
             
             
             
          
             
         
              
        
=> SELECT *FROM accounts WHERE client = 'bob';
id | client | amount
−−−−+−−−−−−−−+−−−−−−−−
2 | bob | 200.00
3 | bob | 800.00
(2 rows)
      
=> BEGIN;
=> UPDATE accounts SET amount = amount - 100 WHERE id = 3;
             
         

    
=> UPDATE accounts SET amount = amount * 1.01
WHERE client IN (
SELECT client
FROM accounts
GROUP BY client
HAVING sum(amount) >= 1000
);
             
           
             
             
           

            
                
 
      
=> COMMIT;
=> SELECT *FROM accounts WHERE client = 'bob';
id | client | amount
−−−−+−−−−−−−−+−−−−−−−−−−
2 | bob | 202.0000
3 | bob | 707.0000
(2 rows)
              
            
               
                
              
   
           
           
 

 
             
          
             
         
=> BEGIN;
=> SELECT amount FROM accounts WHERE id = 1;
amount
−−−−−−−−
800.00
(1 row)
      
=> BEGIN;
=> SELECT amount FROM accounts WHERE id = 1;
amount
−−−−−−−−
800.00
(1 row)
          
 
=> UPDATE accounts SET amount = 800.00 + 100 WHERE id = 1
RETURNING amount;
amount
−−−−−−−−
900.00
(1 row)
UPDATE 1
=> COMMIT;
     
=> UPDATE accounts SET amount = 800.00 + 100 WHERE id = 1
RETURNING amount;
amount
−−−−−−−−
900.00
(1 row)
UPDATE 1

    
=> COMMIT;
            
            
             

 
           
           
             
            
  
=> BEGIN;
=> UPDATE accounts SET amount = 200.00 WHERE id = 2;
=> UPDATE accounts SET amount = 800.00 WHERE id = 3;
=> INSERT INTO accounts VALUES
(4, 'charlie', 100.00);
=> SELECT *FROM accounts ORDER BY id;
id | client | amount
−−−−+−−−−−−−−−+−−−−−−−−
1 | alice | 900.00
2 | bob | 200.00
3 | bob | 800.00
4 | charlie | 100.00
(4 rows)
            
             

=> BEGIN ISOLATION LEVEL REPEATABLE READ;
=> SELECT *FROM accounts ORDER BY id;


 
id | client | amount
−−−−+−−−−−−−−+−−−−−−−−−−
1 | alice | 900.00
2 | bob | 202.0000
3 | bob | 707.0000
(3 rows)
           
  
=> COMMIT;
=> SELECT *FROM accounts ORDER BY id;
id | client | amount
−−−−+−−−−−−−−+−−−−−−−−−−
1 | alice | 900.00
2 | bob | 202.0000
3 | bob | 707.0000
(3 rows)
=> COMMIT;
              
             
   
              
               
             
               
               
           
        
=> SELECT *FROM accounts WHERE client = 'bob';
id | client | amount
−−−−+−−−−−−−−+−−−−−−−−
2 | bob | 200.00
3 | bob | 800.00
(2 rows)
=> BEGIN;

    
=> UPDATE accounts SET amount = amount - 100.00 WHERE id = 3;
=> BEGIN ISOLATION LEVEL REPEATABLE READ;
=> UPDATE accounts SET amount = amount * 1.01
WHERE client IN (
SELECT client
FROM accounts
GROUP BY client
HAVING sum(amount) >= 1000
);
=> COMMIT;
ERROR: could not serialize access due to concurrent update
=> ROLLBACK;
   
=> SELECT *FROM accounts WHERE client = 'bob';
id | client | amount
−−−−+−−−−−−−−+−−−−−−−−
2 | bob | 200.00
3 | bob | 700.00
(2 rows)
              
 
               
 
=> BEGIN ISOLATION LEVEL REPEATABLE READ;
=> SELECT amount FROM accounts WHERE id = 1;
amount
−−−−−−−−
900.00
(1 row)
=> BEGIN ISOLATION LEVEL REPEATABLE READ;

 
=> SELECT amount FROM accounts WHERE id = 1;
amount
−−−−−−−−
900.00
(1 row)
=> UPDATE accounts SET amount = 900.00 + 100.00 WHERE id = 1
RETURNING amount;
amount
−−−−−−−−−
1000.00
(1 row)
UPDATE 1
=> COMMIT;
=> UPDATE accounts SET amount = 900.00 + 100.00 WHERE id = 1
RETURNING amount;
ERROR: could not serialize access due to concurrent update
=> ROLLBACK;
           
             
          

           
            
             
             
       
     
            
             
         
=> BEGIN ISOLATION LEVEL REPEATABLE READ;

    
=> SELECT sum(amount) FROM accounts WHERE client = 'bob';
sum
−−−−−−−−
900.00
(1 row)
      
=> BEGIN ISOLATION LEVEL REPEATABLE READ;
=> SELECT sum(amount) FROM accounts WHERE client = 'bob';
sum
−−−−−−−−
900.00
(1 row)
             
=> UPDATE accounts SET amount = amount - 600.00 WHERE id = 2;
            

=> UPDATE accounts SET amount = amount - 600.00 WHERE id = 3;
=> COMMIT;
=> COMMIT;
=> SELECT *FROM accounts WHERE client = 'bob';
id | client | amount
−−−−+−−−−−−−−+−−−−−−−−−
2 | bob | −400.00
3 | bob | 100.00
(2 rows)
           
   
         
            
              
       

 
     
=> UPDATE accounts SET amount = 900.00 WHERE id = 2;
=> SELECT *FROM accounts WHERE client = 'bob';
id | client | amount
−−−−+−−−−−−−−+−−−−−−−−
3 | bob | 100.00
2 | bob | 900.00
(2 rows)
            
        
=> BEGIN ISOLATION LEVEL REPEATABLE READ;
-- 1
=> UPDATE accounts SET amount = amount + (
SELECT sum(amount) FROM accounts WHERE client = 'bob'
) * 0.01
WHERE id = 2;
           
  
=> BEGIN ISOLATION LEVEL REPEATABLE READ;
-- 2
=> UPDATE accounts SET amount = amount - 100.00 WHERE id = 3;
=> COMMIT;
              
             
             
     
            
           
=> BEGIN ISOLATION LEVEL REPEATABLE READ;
-- 3
=> SELECT *FROM accounts WHERE client = 'alice';
id | client | amount
−−−−+−−−−−−−−+−−−−−−−−−
1 | alice | 1000.00
(1 row)
        

    
=> COMMIT;
             
            
                
            
             
        
=> SELECT *FROM accounts WHERE client = 'bob';
id | client | amount
−−−−+−−−−−−−−+−−−−−−−−
2 | bob | 900.00
3 | bob | 0.00
(2 rows)
=> COMMIT;

          
              
          
             
           
        
             
  
=> BEGIN ISOLATION LEVEL SERIALIZABLE;
=> SELECT sum(amount) FROM accounts WHERE client = 'bob';
sum
−−−−−−−−−−
910.0000
(1 row)


 
=> BEGIN ISOLATION LEVEL SERIALIZABLE;
=> SELECT sum(amount) FROM accounts WHERE client = 'bob';
sum
−−−−−−−−−−
910.0000
(1 row)
=> UPDATE accounts SET amount = amount - 600.00 WHERE id = 2;
=> UPDATE accounts SET amount = amount - 600.00 WHERE id = 3;
=> COMMIT;
COMMIT
=> COMMIT;
ERROR: could not serialize access due to read/write dependencies
among transactions
DETAIL: Reason code: Canceled on identification as a pivot, during
commit attempt.
HINT: The transaction might succeed if retried.
            
       
          
           
             

             
  
=> UPDATE accounts SET amount = 900.00 WHERE id = 2;
=> UPDATE accounts SET amount = 100.00 WHERE id = 3;
=> SELECT *FROM accounts WHERE client = 'bob' ORDER BY id;
id | client | amount
−−−−+−−−−−−−−+−−−−−−−−
2 | bob | 900.00
3 | bob | 100.00
(2 rows)
=> BEGIN ISOLATION LEVEL SERIALIZABLE;
-- 1

    
=> UPDATE accounts SET amount = amount + (
SELECT sum(amount) FROM accounts WHERE client = 'bob'
) * 0.01
WHERE id = 2;
=> BEGIN ISOLATION LEVEL SERIALIZABLE;
-- 2
=> UPDATE accounts SET amount = amount - 100.00 WHERE id = 3;
=> COMMIT;
          
=> BEGIN ISOLATION LEVEL SERIALIZABLE READ ONLY DEFERRABLE;
-- 3
=> SELECT *FROM accounts WHERE client = 'alice';
           
  
             

=> COMMIT;
id | client | amount
−−−−+−−−−−−−−+−−−−−−−−−
1 | alice | 1000.00
(1 row)
=> SELECT *FROM accounts WHERE client = 'bob';
id | client | amount
−−−−+−−−−−−−−+−−−−−−−−−−
2 | bob | 910.0000
3 | bob | 0.00
(2 rows)
=> COMMIT;
              
         
           

            
           

 
            
           
          
               
           
           
    
           
            
             
          
              
         
              
   read
committed
   
           
             
            
           

     
             
              
             
          
            
            
              
              
             
               

     
           
         
          
              
          
         
              
         
             
             
             
          
         
              
    

3
Pages and Tuples
  
            
 
    
 
  
 
 
              
               
    
          
           




  
=> CREATE EXTENSION pageinspect;
=> SELECT lower, upper, special, pagesize
FROM page_header(get_raw_page('accounts',0));
lower | upper | special | pagesize
−−−−−−−+−−−−−−−+−−−−−−−−−+−−−−−−−−−−
152 | 6904 | 8192 | 8192
(1 row)

    
 

 





 
               
             
      
             
             
           
          

            
        

   
               
          
             
             
 
              
           

 
               
   
           
             
              

                
            
           

           
           
                
           
          
       
 
     

   
 
             
                
     
   
           
     
           
        
         
           
              
                
              
            
         
             
             
        
              
         
 
          
           
            
  


   
         
             
 
              
              
     
=> CREATE TABLE padding(
b1 boolean,
i1 integer,
b2 boolean,
i2 integer
);
=> INSERT INTO padding VALUES (true,1,false,2);
=> SELECT lp_len FROM heap_page_items(get_raw_page('padding', 0));
lp_len
−−−−−−−−
40
(1 row)
          
     
              
            
             
               
    
                
             
        
           
=> DROP TABLE padding;
=> CREATE TABLE padding(
i1 integer,
i2 integer,
b1 boolean,
b2 boolean
);

   
=> INSERT INTO padding VALUES (1,2,true,false);
=> SELECT lp_len FROM heap_page_items(get_raw_page('padding', 0));
lp_len
−−−−−−−−
34
(1 row)
          
            
           
   
            
             
            
  
                

               
    
           
            
              
                  
 
            
            
   
  


   
=> CREATE TABLE t(
id integer GENERATED ALWAYS AS IDENTITY,
s text
);
=> CREATE INDEX ON t(s);

     
=> BEGIN;
=> INSERT INTO t(s) VALUES ('FOO');
     
=>
-- txid_current() before v.13
SELECT pg_current_xact_id();
pg_current_xact_id
−−−−−−−−−−−−−−−−−−−−
776
(1 row)
             
              
              
  
            
               
   
=> SELECT *
FROM heap_page_items(get_raw_page('t',0)) \gx
−[ RECORD 1 ]−−−−−−−−−−−−−−−−−−−
lp | 1
lp_off | 8160
lp_flags | 1
lp_len | 32
t_xmin | 776
t_xmax | 0
t_field3 | 0
t_ctid | (0,1)

   
t_infomask2 | 2
t_infomask | 2050
t_hoff | 24
t_bits |
t_oid |
t_data | \x0100000009464f4f
            

=> SELECT '(0,'||lp||')' AS ctid,
CASE lp_flags
WHEN 0THEN 'unused'
WHEN 1THEN 'normal'
WHEN 2THEN 'redirect to '||lp_off
WHEN 3THEN 'dead'
END AS state,
t_xmin as xmin,
t_xmax as xmax,
(t_infomask & 256) > 0 AS xmin_committed,
(t_infomask & 512) > 0 AS xmin_aborted,
(t_infomask & 1024) > 0 AS xmax_committed,
(t_infomask & 2048) > 0 AS xmax_aborted
FROM heap_page_items(get_raw_page('t',0)) \gx
−[ RECORD 1 ]−−+−−−−−−−
ctid | (0,1)
state | normal
xmin | 776
xmax | 0
xmin_committed | f
xmin_aborted | f
xmax_committed | f
xmax_aborted | t
      
             
 
               
     
             
         

   
         
     
         
               
      
             
             
               
           
             
            
        
              
             
             
 
               
             
           
=> CREATE FUNCTION heap_page(relname text, pageno integer)
RETURNS TABLE(ctid tid, state text, xmin text, xmax text)
AS $$
SELECT (pageno,lp)::text::tid AS ctid,
CASE lp_flags
WHEN 0THEN 'unused'
WHEN 1THEN 'normal'
WHEN 2THEN 'redirect to '||lp_off
WHEN 3THEN 'dead'
END AS state,
t_xmin || CASE
WHEN (t_infomask & 256) > 0 THEN ' c'
WHEN (t_infomask & 512) > 0 THEN ' a'
ELSE ''
END AS xmin,

   
t_xmax || CASE
WHEN (t_infomask & 1024) > 0 THEN ' c'
WHEN (t_infomask & 2048) > 0 THEN ' a'
ELSE ''
END AS xmax
FROM heap_page_items(get_raw_page(relname,pageno))
ORDER BY lp;
$$ LANGUAGE sql;
           
=> SELECT *FROM heap_page('t',0);
ctid | state | xmin | xmax
−−−−−−−+−−−−−−−−+−−−−−−+−−−−−−
(0,1) | normal | 776 | 0 a
(1 row)
             
    
=> SELECT xmin, xmax, * FROM t;
xmin | xmax | id | s
−−−−−−+−−−−−−+−−−−+−−−−−
776 | 0 | 1 | FOO
(1 row)

           
           
          
          
             
         
             




   
              
        
           
 
           
             
   
         
          
            
            
       
             
   
             
             
           
      
                
           
       
             
               
             
             
              
             


   
             
             
 
         
=> COMMIT;
              
    
=> SELECT *FROM heap_page('t',0);
ctid | state | xmin | xmax
−−−−−−−+−−−−−−−−+−−−−−−+−−−−−−
(0,1) | normal | 776 | 0 a
(1 row)
            
            
 
=> SELECT *FROM t;
id | s
−−−−+−−−−−
1 | FOO
(1 row)
=> SELECT *FROM heap_page('t',0);
ctid | state | xmin | xmax
−−−−−−−+−−−−−−−−+−−−−−−−+−−−−−−
(0,1) | normal | 776 c | 0 a
(1 row)

               
          

   
               
                

  
=> BEGIN;
=> DELETE FROM t;
=> SELECT pg_current_xact_id();
pg_current_xact_id
−−−−−−−−−−−−−−−−−−−−
777
(1 row)
             
      
=> SELECT *FROM heap_page('t',0);
ctid | state | xmin | xmax
−−−−−−−+−−−−−−−−+−−−−−−−+−−−−−−
(0,1) | normal | 776 c | 777
(1 row)

            
               
          
             
=> ROLLBACK;
=> SELECT *FROM heap_page('t',0);
ctid | state | xmin | xmax
−−−−−−−+−−−−−−−−+−−−−−−−+−−−−−−
(0,1) | normal | 776 c | 777
(1 row)

   
             
             
         
=> SELECT *FROM t;
id | s
−−−−+−−−−−
1 | FOO
(1 row)
=> SELECT *FROM heap_page('t',0);
ctid | state | xmin | xmax
−−−−−−−+−−−−−−−−+−−−−−−−+−−−−−−−
(0,1) | normal | 776 c | 777 a
(1 row)

               
   
=> BEGIN;
=> UPDATE tSET s = 'BAR';
=> SELECT pg_current_xact_id();
pg_current_xact_id
−−−−−−−−−−−−−−−−−−−−
778
(1 row)
       
=> SELECT *FROM t;
id | s
−−−−+−−−−−
1 | BAR
(1 row)

   
     
=> SELECT *FROM heap_page('t',0);
ctid | state | xmin | xmax
−−−−−−−+−−−−−−−−+−−−−−−−+−−−−−−
(0,1) | normal | 776 c | 778
(0,2) | normal | 778 | 0 a
(2 rows)
           
               
            
  
      
=> COMMIT;
 
            
              
              
            
        
           
              
=> CREATE FUNCTION index_page(relname text, pageno integer)
RETURNS TABLE(itemoffset smallint, htid tid)
AS $$
SELECT itemoffset,
htid
-- ctid before v.13
FROM bt_page_items(relname,pageno);
$$ LANGUAGE sql;
           

 
=> SELECT *FROM index_page('t_s_idx',1);
itemoffset | htid
−−−−−−−−−−−−+−−−−−−−
1 | (0,2)
2 | (0,1)
(2 rows)
             
 
              
              
              
      
               
              
           
          
  
       
              
            
           
          
      
=> BEGIN;


   
=>
-- txid_current_if_assigned() before v.13
SELECT pg_current_xact_id_if_assigned();
pg_current_xact_id_if_assigned
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
(1 row)
            
              
           
      
           
=> UPDATE accounts
SET amount = amount - 1.00;
=> SELECT pg_current_xact_id_if_assigned();
pg_current_xact_id_if_assigned
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
780
(1 row)
=> COMMIT;
 

          
          
             
         
        
       


 
              
            
         
               
         
         
             
        
          
              
                
            

         
=> TRUNCATE TABLE t;
=> BEGIN;
=> INSERT INTO t(s) VALUES ('FOO');
=> SELECT pg_current_xact_id();
pg_current_xact_id
−−−−−−−−−−−−−−−−−−−−
782
(1 row)
      
=> SAVEPOINT sp;
=> INSERT INTO t(s) VALUES ('XYZ');
=> SELECT pg_current_xact_id();
pg_current_xact_id
−−−−−−−−−−−−−−−−−−−−
782
(1 row)
           
   


   
=> SELECT *
FROM heap_page('t',0) p
LEFT JOIN tON p.ctid = t.ctid;
ctid | state | xmin | xmax | id | s
−−−−−−−+−−−−−−−−+−−−−−−+−−−−−−+−−−−+−−−−−
(0,1) | normal | 782 | 0 a | 2 | FOO
(0,2) | normal | 783 | 0 a | 3 | XYZ
(2 rows)
          
=> ROLLBACK TO sp;
=> INSERT INTO t(s) VALUES ('BAR');
=> SELECT *
FROM heap_page('t',0) p
LEFT JOIN tON p.ctid = t.ctid;
ctid | state | xmin | xmax | id | s
−−−−−−−+−−−−−−−−+−−−−−−+−−−−−−+−−−−+−−−−−
(0,1) | normal | 782 | 0 a | 2 | FOO
(0,2) | normal | 783 | 0 a | |
(0,3) | normal | 784 | 0 a | 4 | BAR
(3 rows)
          
  
=> COMMIT;
=> SELECT *FROM t;
id | s
−−−−+−−−−−
2 | FOO
4 | BAR
(2 rows)
=> SELECT *FROM heap_page('t',0);
ctid | state | xmin | xmax
−−−−−−−+−−−−−−−−+−−−−−−−+−−−−−−
(0,1) | normal | 782 c | 0 a
(0,2) | normal | 783 a | 0 a
(0,3) | normal | 784 c | 0 a
(3 rows)

 
           
            
     
=> BEGIN;
BEGIN
=> BEGIN;
WARNING: there is already a transaction in progress
BEGIN
=> COMMIT;
COMMIT
=> COMMIT;
WARNING: there is no transaction in progress
COMMIT
        
         
  
         
=> BEGIN;
=> SELECT *FROM t;
id | s
−−−−+−−−−−
2 | FOO
4 | BAR
(2 rows)
=> UPDATE tSET s = repeat('X', 1/(id-4));
ERROR: division by zero
          
  
=> SELECT *FROM t;
ERROR: current transaction is aborted, commands ignored until end
of transaction block

   
              
   
=> COMMIT;
ROLLBACK
           
            
            
     
              
   
=> SELECT *FROM heap_page('t',0);
ctid | state | xmin | xmax
−−−−−−−+−−−−−−−−+−−−−−−−+−−−−−−
(0,1) | normal | 782 c | 785
(0,2) | normal | 783 a | 0 a
(0,3) | normal | 784 c | 0 a
(0,4) | normal | 785 | 0 a
(4 rows)
            
          
=> \set ON_ERROR_ROLLBACK on
=> BEGIN;
=> UPDATE tSET s = repeat('X', 1/(id-4));
ERROR: division by zero
=> SELECT *FROM t;
id | s
−−−−+−−−−−
2 | FOO
4 | BAR
(2 rows)
=> COMMIT;
COMMIT

 
            
              
             
  

4
Snapshots
   
             
             
           
            
        
           
           
 
            
           
           
             
  
xid
snapshot1 snapshot2
statement1 statement2
Read Committed
xid
snapshot
statement1 statement2
Repeatable Read,
Serializable

   
   
             
          
               
          
            
     
            
            
           
            
   
            
          
           
    
           
       
xid
123
snapshot
        
          



 
            
  
           
           

  
           
            
            
            
       off   
                
            
            
          
              
           
            
               
               
              
            
       
             
           
      




  
xid
1 2 3
at snapshot creation…
xid
1 2 3
…and some time later
               
              
            
           
          
                
          
        
             
              
       
            
              
 
            
           
           
           
       
              
          
               
        
       
  

 
            
          
    
xid
1 2 3
xmin xmax
xip_list
          
       
=> TRUNCATE TABLE accounts;
            
=> BEGIN;
=> INSERT INTO accounts VALUES (1, 'alice', 1000.00);
=> SELECT pg_current_xact_id();
pg_current_xact_id
−−−−−−−−−−−−−−−−−−−−
790
(1 row)
           

=> BEGIN;
=> INSERT INTO accounts VALUES (2, 'bob', 100.00);
=> SELECT pg_current_xact_id();
pg_current_xact_id
−−−−−−−−−−−−−−−−−−−−
791
(1 row)
=> COMMIT;

  
           
               
  
=> BEGIN ISOLATION LEVEL REPEATABLE READ;
=>
-- txid_current_snapshot() before v.13
SELECT pg_current_snapshot();
pg_current_snapshot
−−−−−−−−−−−−−−−−−−−−−
790:792:790
(1 row)
        
            
   
        
=> COMMIT;
            
    
=> BEGIN;
=> UPDATE accounts SET amount = amount + 100 WHERE id = 2;
=> SELECT pg_current_xact_id();
pg_current_xact_id
−−−−−−−−−−−−−−−−−−−−
792
(1 row)
=> COMMIT;
     
=> SELECT ctid, * FROM accounts;
ctid | id | client | amount
−−−−−−−+−−−−+−−−−−−−−+−−−−−−−−
(0,2) | 2 | bob | 100.00
(1 row)

 
      
=> SELECT *FROM heap_page('accounts',0);
ctid | state | xmin | xmax
−−−−−−−+−−−−−−−−+−−−−−−−+−−−−−−−
(0,1) | normal | 790 c | 0 a
(0,2) | normal | 791 c | 792 c
(0,3) | normal | 792 c | 0 a
(3 rows)
            
           
     
             
     
          
    
             
         
            
         
              
             
          
            
=> COMMIT;
    
            
             
             
          

     
         
           
           
            
               
           
            
             
           
=> BEGIN;
=> INSERT INTO accounts VALUES (3, 'charlie', 100.00);
=> SELECT pg_current_xact_id();
pg_current_xact_id
−−−−−−−−−−−−−−−−−−−−
793
(1 row)
              
=> DECLARE cCURSOR FOR SELECT count(*) FROM accounts;
   
=> INSERT INTO accounts VALUES (4, 'charlie', 200.00);
              
          
=> SELECT xmin, CASE WHEN xmin = 793 THEN cmin END cmin, *
FROM accounts;
xmin | cmin | id | client | amount
−−−−−−+−−−−−−+−−−−+−−−−−−−−−+−−−−−−−−−
790 | | 1 | alice | 1000.00
792 | | 2 | bob | 200.00
793 | 0 | 3 | charlie | 100.00
793 | 1 | 4 | charlie | 200.00
(4 rows)


 
              
             
 
=> FETCH c;
count
−−−−−−−
3
(1 row)
              
     
  
            
                
             
    
            
               

             
             
   
               
           
      
=> BEGIN;
=> SELECT backend_xmin FROM pg_stat_activity
WHERE pid = pg_backend_pid();
backend_xmin
−−−−−−−−−−−−−−
793
(1 row)

  
             
            
             
             
         
   
           
              
           
              
              
   
xid
1 2 345678 9 10
database
horizon
outdated tuples
that can be vacuumed
   
             
            
    
  

 
          
               
   
          
   
                
             
     
            
              
            
             
            

=> SELECT pg_current_xact_id();
pg_current_xact_id
−−−−−−−−−−−−−−−−−−−−
794
(1 row)
=> SELECT backend_xmin FROM pg_stat_activity
WHERE pid = pg_backend_pid();
backend_xmin
−−−−−−−−−−−−−−
793
(1 row)
            
    
=> COMMIT;
=> SELECT backend_xmin FROM pg_stat_activity
WHERE pid = pg_backend_pid();
backend_xmin
−−−−−−−−−−−−−−
795
(1 row)

   
           
              
   
           
           
           
         
   
=> BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ;
=> SELECT 1;
-- a snapshot for the transaction is taken
=> ALTER TABLE accounts
ALTER amount SET NOT NULL;
=> INSERT INTO accounts(client, amount)
VALUES ('alice', NULL);
ERROR: null value in column "amount" of relation "accounts"
violates not−null constraint
DETAIL: Failing row contains (1, alice, null).
=> ROLLBACK;
           
             
            
            
             
          
        
            
  

 
  
           
                
          
         
          
       
          
      
=> BEGIN ISOLATION LEVEL REPEATABLE READ;
=> SELECT count(*) FROM accounts;
count
−−−−−−−
4
(1 row)
=> SELECT pg_export_snapshot();
pg_export_snapshot
−−−−−−−−−−−−−−−−−−−−−
00000004−0000006E−1
(1 row)
           
            
            
  
=> DELETE FROM accounts;
=> BEGIN ISOLATION LEVEL REPEATABLE READ;
=> SET TRANSACTION SNAPSHOT '00000004-0000006E-1';
             
         

  
=> SELECT count(*) FROM accounts;
count
−−−−−−−
4
(1 row)
            
            
            
=> COMMIT;
=> COMMIT;

5
Page Pruning and HOT Updates
  
            
        
            
           
         100   

               
              
      
            
               
             
            

              
           
            
             
  
  

  
            
          
=> CREATE TABLE hot(id integer, s char(2000)) WITH (fillfactor = 75);
=> CREATE INDEX hot_id ON hot(id);
=> CREATE INDEX hot_s ON hot(s);
             
              
                 
  
        
=> INSERT INTO hot VALUES (1, 'A');
=> UPDATE hot SET s = 'B';
=> UPDATE hot SET s = 'C';
=> UPDATE hot SET s = 'D';
     
=> SELECT *FROM heap_page('hot',0);
ctid | state | xmin | xmax
−−−−−−−+−−−−−−−−+−−−−−−−+−−−−−−−
(0,1) | normal | 801 c | 802 c
(0,2) | normal | 802 c | 803 c
(0,3) | normal | 803 c | 804
(0,4) | normal | 804 | 0 a
(4 rows)
            
             
     
=> SELECT upper, pagesize FROM page_header(get_raw_page('hot',0));
upper | pagesize
−−−−−−−+−−−−−−−−−−
64 | 8192
(1 row)
            
         

     
=> UPDATE hot SET s = 'E';
=> SELECT *FROM heap_page('hot',0);
ctid | state | xmin | xmax
−−−−−−−+−−−−−−−−+−−−−−−−+−−−−−−
(0,1) | dead | |
(0,2) | dead | |
(0,3) | dead | |
(0,4) | normal | 804 c | 805
(0,5) | normal | 805 | 0 a
(5 rows)
          
             
            
   
              
           
                 

=> SELECT *FROM index_page('hot_s',1);
itemoffset | htid
−−−−−−−−−−−−+−−−−−−−
1 | (0,1)
2 | (0,2)
3 | (0,3)
4 | (0,4)
5 | (0,5)
(5 rows)
         
=> SELECT *FROM index_page('hot_id',1);
itemoffset | htid
−−−−−−−−−−−−+−−−−−−−
1 | (0,1)
2 | (0,2)
3 | (0,3)
4 | (0,4)
5 | (0,5)
(5 rows)

  
             
              
              
               
   
             
  
=> DROP FUNCTION index_page(text, integer);
=> CREATE FUNCTION index_page(relname text, pageno integer)
RETURNS TABLE(itemoffset smallint, htid tid, dead boolean)
AS $$
SELECT itemoffset,
htid,
dead
-- starting from v.13
FROM bt_page_items(relname,pageno);
$$ LANGUAGE sql;
=> SELECT *FROM index_page('hot_id',1);
itemoffset | htid | dead
−−−−−−−−−−−−+−−−−−−−+−−−−−−
1 | (0,1) | f
2 | (0,2) | f
3 | (0,3) | f
4 | (0,4) | f
5 | (0,5) | f
(5 rows)
                 
    
=> EXPLAIN (analyze, costs off, timing off, summary off)
SELECT *FROM hot WHERE id = 1;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Index Scan using hot_id on hot (actual rows=1 loops=1)
Index Cond: (id = 1)
(2 rows)
  

     
=> SELECT *FROM index_page('hot_id',1);
itemoffset | htid | dead
−−−−−−−−−−−−+−−−−−−−+−−−−−−
1 | (0,1) | t
2 | (0,2) | t
3 | (0,3) | t
4 | (0,4) | t
5 | (0,5) | f
(5 rows)
            
             
        
  
              
            
            
         
          
       
         
                
           
       
               
             
              
             
                
 


  
              
              
            
       
             
   
=> DROP INDEX hot_s;
=> TRUNCATE TABLE hot;
            
            
=> DROP FUNCTION heap_page(text,integer);
=> CREATE FUNCTION heap_page(relname text, pageno integer)
RETURNS TABLE(
ctid tid, state text,
xmin text, xmax text,
hhu text, hot text, t_ctid tid
)AS $$
SELECT (pageno,lp)::text::tid AS ctid,
CASE lp_flags
WHEN 0THEN 'unused'
WHEN 1THEN 'normal'
WHEN 2THEN 'redirect to '||lp_off
WHEN 3THEN 'dead'
END AS state,
t_xmin || CASE
WHEN (t_infomask & 256) > 0 THEN ' c'
WHEN (t_infomask & 512) > 0 THEN ' a'
ELSE ''
END AS xmin,
t_xmax || CASE
WHEN (t_infomask & 1024) > 0 THEN ' c'
WHEN (t_infomask & 2048) > 0 THEN ' a'
ELSE ''
END AS xmax,
CASE WHEN (t_infomask2 & 16384) > 0 THEN 't' END AS hhu,
CASE WHEN (t_infomask2 & 32768) > 0 THEN 't' END AS hot,
t_ctid
FROM heap_page_items(get_raw_page(relname,pageno))
ORDER BY lp;
$$ LANGUAGE sql;

     
      
=> INSERT INTO hot VALUES (1, 'A');
=> UPDATE hot SET s = 'B';
       
            

             

=> SELECT *FROM heap_page('hot',0);
ctid | state | xmin | xmax | hhu | hot | t_ctid
−−−−−−−+−−−−−−−−+−−−−−−−+−−−−−−+−−−−−+−−−−−+−−−−−−−−
(0,1) | normal | 812 c | 813 | t | | (0,2)
(0,2) | normal | 813 | 0 a | | t | (0,2)
(2 rows)
             
=> UPDATE hot SET s = 'C';
=> UPDATE hot SET s = 'D';
=> SELECT *FROM heap_page('hot',0);
ctid | state | xmin | xmax | hhu | hot | t_ctid
−−−−−−−+−−−−−−−−+−−−−−−−+−−−−−−−+−−−−−+−−−−−+−−−−−−−−
(0,1) | normal | 812 c | 813 c | t | | (0,2)
(0,2) | normal | 813 c | 814 c | t | t | (0,3)
(0,3) | normal | 814 c | 815 | t | t | (0,4)
(0,4) | normal | 815 | 0 a | | t | (0,4)
(4 rows)
              
=> SELECT *FROM index_page('hot_id',1);
itemoffset | htid | dead
−−−−−−−−−−−−+−−−−−−−+−−−−−−
1 | (0,1) | f
(1 row)

     
              
            
             
            
          
     
         
  
             
             
               
              
   
          
               
       
=> UPDATE hot SET s = 'E';
=> SELECT *FROM heap_page('hot',0);
ctid | state | xmin | xmax | hhu | hot | t_ctid
−−−−−−−+−−−−−−−−−−−−−−−+−−−−−−−+−−−−−−+−−−−−+−−−−−+−−−−−−−−
(0,1) | redirect to 4 | | | | |
(0,2) | normal | 816 | 0 a | | t | (0,2)
(0,3) | unused | | | | |
(0,4) | normal | 815 c | 816 | t | t | (0,2)
(4 rows)
            
         
            
          

     
    
=> UPDATE hot SET s = 'F';
=> UPDATE hot SET s = 'G';
=> SELECT *FROM heap_page('hot',0);
ctid | state | xmin | xmax | hhu | hot | t_ctid
−−−−−−−+−−−−−−−−−−−−−−−+−−−−−−−+−−−−−−−+−−−−−+−−−−−+−−−−−−−−
(0,1) | redirect to 4 | | | | |
(0,2) | normal | 816 c | 817 c | t | t | (0,3)
(0,3) | normal | 817 c | 818 | t | t | (0,5)
(0,4) | normal | 815 c | 816 c | t | t | (0,2)
(0,5) | normal | 818 | 0 a | | t | (0,5)
(5 rows)
        
=> UPDATE hot SET s = 'H';
=> SELECT *FROM heap_page('hot',0);
ctid | state | xmin | xmax | hhu | hot | t_ctid
−−−−−−−+−−−−−−−−−−−−−−−+−−−−−−−+−−−−−−+−−−−−+−−−−−+−−−−−−−−
(0,1) | redirect to 5 | | | | |
(0,2) | normal | 819 | 0 a | | t | (0,2)
(0,3) | unused | | | | |
(0,4) | unused | | | | |
(0,5) | normal | 818 c | 819 | t | t | (0,2)
(5 rows)
                
 
            
             
                 
         

   
   
               
              
  
         
  
=> BEGIN ISOLATION LEVEL REPEATABLE READ;
=> SELECT 1;
           
=> UPDATE hot SET s = 'I';
=> UPDATE hot SET s = 'J';
=> UPDATE hot SET s = 'K';
=> SELECT *FROM heap_page('hot',0);
ctid | state | xmin | xmax | hhu | hot | t_ctid
−−−−−−−+−−−−−−−−−−−−−−−+−−−−−−−+−−−−−−−+−−−−−+−−−−−+−−−−−−−−
(0,1) | redirect to 2 | | | | |
(0,2) | normal | 819 c | 820 c | t | t | (0,3)
(0,3) | normal | 820 c | 821 c | t | t | (0,4)
(0,4) | normal | 821 c | 822 | t | t | (0,5)
(0,5) | normal | 822 | 0 a | | t | (0,5)
(5 rows)
             
          
=> UPDATE hot SET s = 'L';
=> COMMIT;
-- the snapshot is not required anymore

     
=> SELECT *FROM heap_page('hot',0);
ctid | state | xmin | xmax | hhu | hot | t_ctid
−−−−−−−+−−−−−−−−−−−−−−−+−−−−−−−+−−−−−−−+−−−−−+−−−−−+−−−−−−−−
(0,1) | redirect to 2 | | | | |
(0,2) | normal | 819 c | 820 c | t | t | (0,3)
(0,3) | normal | 820 c | 821 c | t | t | (0,4)
(0,4) | normal | 821 c | 822 c | t | t | (0,5)
(0,5) | normal | 822 c | 823 | | t | (1,1)
(5 rows)
          
=> SELECT *FROM heap_page('hot',1);
ctid | state | xmin | xmax | hhu | hot | t_ctid
−−−−−−−+−−−−−−−−+−−−−−−+−−−−−−+−−−−−+−−−−−+−−−−−−−−
(1,1) | normal | 823 | 0 a | | | (1,1)
(1 row)
               
                
           
=> SELECT *FROM index_page('hot_id',1);
itemoffset | htid | dead
−−−−−−−−−−−−+−−−−−−−+−−−−−−
1 | (0,1) | f
2 | (1,1) | f
(2 rows)
    
             
          
      
             
              
              


    
              
               
       
            
            
             
              
   
               
            
            
           
               
           
                
            
             
            
              
 
   
   


6
Vacuum and Autovacuum
 
                
           
             
          
          
      
           
             
            
          
          
               
                
           
      
              
       




 
=> CREATE TABLE vac(
id integer,
s char(100)
)
WITH (autovacuum_enabled = off);
=> CREATE INDEX vac_s ON vac(s);
         
           
 
       
=> INSERT INTO vac(id,s) VALUES (1,'A');
=> UPDATE vac SET s = 'B';
=> UPDATE vac SET s = 'C';
     
=> SELECT *FROM heap_page('vac',0);
ctid | state | xmin | xmax | hhu | hot | t_ctid
−−−−−−−+−−−−−−−−+−−−−−−−+−−−−−−−+−−−−−+−−−−−+−−−−−−−−
(0,1) | normal | 826 c | 827 c | | | (0,2)
(0,2) | normal | 827 c | 828 | | | (0,3)
(0,3) | normal | 828 | 0 a | | | (0,3)
(3 rows)
      
=> SELECT *FROM index_page('vac_s',1);
itemoffset | htid | dead
−−−−−−−−−−−−+−−−−−−−+−−−−−−
1 | (0,1) | f
2 | (0,2) | f
3 | (0,3) | f
(3 rows)
           
=> VACUUM vac;

   
=> SELECT *FROM heap_page('vac',0);
ctid | state | xmin | xmax | hhu | hot | t_ctid
−−−−−−−+−−−−−−−−+−−−−−−−+−−−−−−+−−−−−+−−−−−+−−−−−−−−
(0,1) | unused | | | | |
(0,2) | unused | | | | |
(0,3) | normal | 828 c | 0 a | | | (0,3)
(3 rows)
              
              
=> SELECT *FROM index_page('vac_s',1);
itemoffset | htid | dead
−−−−−−−−−−−−+−−−−−−−+−−−−−−
1 | (0,3) | f
(1 row)
               

               
 
=> CREATE EXTENSION pg_visibility;
=> SELECT all_visible
FROM pg_visibility_map('vac',0);
all_visible
−−−−−−−−−−−−−
t
(1 row)
              
  
=> SELECT flags & 4 > 0 AS all_visible
FROM page_header(get_raw_page('vac',0));
all_visible
−−−−−−−−−−−−−
t
(1 row)

   
   
            
           
       
=> TRUNCATE vac;
=> INSERT INTO vac(id,s) VALUES (1,'A');
=> UPDATE vac SET s = 'B';
             
               
           
       
=> BEGIN;
=> UPDATE accounts SET amount = 0;
=> UPDATE vac SET s = 'C';
            
      
=> VACUUM vac;
=> SELECT *FROM heap_page('vac',0);
ctid | state | xmin | xmax | hhu | hot | t_ctid
−−−−−−−+−−−−−−−−+−−−−−−−+−−−−−−−+−−−−−+−−−−−+−−−−−−−−
(0,1) | unused | | | | |
(0,2) | normal | 833 c | 835 c | | | (0,3)
(0,3) | normal | 835 c | 0 a | | | (0,3)
(3 rows)
=> SELECT *FROM index_page('vac_s',1);
itemoffset | htid | dead
−−−−−−−−−−−−+−−−−−−−+−−−−−−
1 | (0,2) | f
2 | (0,3) | f
(2 rows)

   
                
             
           
=> SELECT backend_xmin FROM pg_stat_activity
WHERE pid = pg_backend_pid();
backend_xmin
−−−−−−−−−−−−−−
834
(1 row)
             
=> VACUUM VERBOSE vac;
INFO: vacuuming "public.vac"
INFO: table "vac": found 0 removable, 2 nonremovable row versions
in 1 out of 1 pages
DETAIL: 1 dead row versions cannot be removed yet, oldest xmin: 834
Skipped 0 pages due to buffer pins, 0 frozen pages.
CPU: user: 0.00 s, system: 0.00 s, elapsed: 0.00 s.
VACUUM
     
         
      
            
            
 
          
  
=> COMMIT;

   
=> VACUUM VERBOSE vac;
INFO: vacuuming "public.vac"
INFO: scanned index "vac_s" to remove 1 row versions
DETAIL: CPU: user: 0.00 s, system: 0.00 s, elapsed: 0.00 s
INFO: table "vac": removed 1 dead item identifiers in 1 pages
DETAIL: CPU: user: 0.00 s, system: 0.00 s, elapsed: 0.00 s
INFO: index "vac_s" now contains 1 row versions in 2 pages
DETAIL: 1 index row versions were removed.
0 index pages were newly deleted.
0 index pages are currently deleted, of which 0 are currently
reusable.
CPU: user: 0.00 s, system: 0.00 s, elapsed: 0.00 s.
INFO: table "vac": found 1 removable, 1 nonremovable row versions
in 1 out of 1 pages
DETAIL: 0 dead row versions cannot be removed yet, oldest xmin: 836
Skipped 0 pages due to buffer pins, 0 frozen pages.
CPU: user: 0.00 s, system: 0.00 s, elapsed: 0.00 s.
VACUUM
           
             
 
=> SELECT *FROM heap_page('vac',0);
ctid | state | xmin | xmax | hhu | hot | t_ctid
−−−−−−−+−−−−−−−−+−−−−−−−+−−−−−−+−−−−−+−−−−−+−−−−−−−−
(0,1) | unused | | | | |
(0,2) | unused | | | | |
(0,3) | normal | 835 c | 0 a | | | (0,3)
(3 rows)
      
=> SELECT *FROM index_page('vac_s',1);
itemoffset | htid | dead
−−−−−−−−−−−−+−−−−−−−+−−−−−−
1 | (0,3) | f
(1 row)

   
  
           
            
          
    
               
              
            
  
 
            
             
               
              
         
               
      64MB   
            
            
            
 
               
             
            
  
  
  

  
                
         
                   
            
         
        512kB  
           
          
            
        
           
            
            
                 
      
            
              
             
      
 
            
             
           
              
              
 


  
  
  

   
                 
            
 
            
                
              
         
            
            
               
 
             
     
              
       

 
            
            
  
          
         
         

            
           
         
  



    
           
            
  
              
  
    
            
             
             
             
        
              
  
          
              
    
         
       
   
    on      
           
            
        on   
          


   
 1min       
           
           
          
           
 3 
           
            
          
 
           
 
            
             
         
            
          
          
     
          
          
           
           
       
           
 
  −1       
        
        


    
           
         
           
           
            
              
             
       
     
             
            
         


          
      
          
            

              
     
50       
  
0.2        


   
        


 
          
               
               

           
               
          
  
  
              
             
            
  
             
         
1000 
0.2 
    


 

    
              
 
    
    
     
           
     
               
           
 
50
0.1
        


 
          
 


          

   
  
            
           
            
        
=> CREATE FUNCTION p(param text, c pg_class) RETURNS float
AS $$
SELECT coalesce(
-- use storage parameter if set
(SELECT option_value
FROM pg_options_to_table(c.reloptions)
WHERE option_name = CASE
-- for TOAST tables the parameter name is different
WHEN c.relkind = 't' THEN 'toast.' ELSE ''
END || param
),
-- else take the configuration parameter value
current_setting(param)
)::float;
$$ LANGUAGE sql;
       
=> CREATE VIEW need_vacuum AS
WITH cAS (
SELECT c.oid,
greatest(c.reltuples, 0) reltuples,
p('autovacuum_vacuum_threshold', c) threshold,
p('autovacuum_vacuum_scale_factor', c) scale_factor,
p('autovacuum_vacuum_insert_threshold', c) ins_threshold,
p('autovacuum_vacuum_insert_scale_factor', c) ins_scale_factor
FROM pg_class c
WHERE c.relkind IN ('r','m','t')
)
SELECT st.schemaname || '.' || st.relname AS tablename,
st.n_dead_tup AS dead_tup,
c.threshold + c.scale_factor * c.reltuples AS max_dead_tup,
st.n_ins_since_vacuum AS ins_tup,
c.ins_threshold + c.ins_scale_factor * c.reltuples AS max_ins_tup,
st.last_autovacuum
FROM pg_stat_all_tables st
JOIN cON c.oid = st.relid;
  

    
            
          

     
=> CREATE VIEW need_analyze AS
WITH cAS (
SELECT c.oid,
greatest(c.reltuples, 0) reltuples,
p('autovacuum_analyze_threshold', c) threshold,
p('autovacuum_analyze_scale_factor', c) scale_factor
FROM pg_class c
WHERE c.relkind IN ('r','m')
)
SELECT st.schemaname || '.' || st.relname AS tablename,
st.n_mod_since_analyze AS mod_tup,
c.threshold + c.scale_factor * c.reltuples AS max_mod_tup,
st.last_autoanalyze
FROM pg_stat_all_tables st
JOIN cON c.oid = st.relid;
        
          
=> ALTER SYSTEM SET autovacuum_naptime = '1s';
=> SELECT pg_reload_conf();
             
     
=> TRUNCATE TABLE vac;
=> INSERT INTO vac(id,s)
SELECT id, 'A' FROM generate_series(1,1000) id;
       
=> SELECT *FROM need_vacuum WHERE tablename = 'public.vac' \gx
−[ RECORD 1 ]−−−+−−−−−−−−−−−
tablename | public.vac
dead_tup | 0
max_dead_tup | 50
ins_tup | 1000
max_ins_tup | 1000
last_autovacuum |

   
          
              
              
=> SELECT reltuples FROM pg_class WHERE relname = 'vac';
reltuples
−−−−−−−−−−−
1
(1 row)
              
           
            
         
             
 
      
=> SELECT *FROM need_analyze WHERE tablename = 'public.vac' \gx
−[ RECORD 1 ]−−−−+−−−−−−−−−−−
tablename | public.vac
mod_tup | 1006
max_mod_tup | 50
last_autoanalyze |
            
               
         
=> ALTER TABLE vac SET (autovacuum_enabled = on);
             
 
=> SELECT reltuples FROM pg_class WHERE relname = 'vac';
reltuples
−−−−−−−−−−−
1000
(1 row)

    
=> SELECT *FROM need_analyze WHERE tablename = 'public.vac' \gx
−[ RECORD 1 ]−−−−+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
tablename | public.vac
mod_tup | 0
max_mod_tup | 150
last_autoanalyze | 2023−03−06 14:00:45.533464+03
    
=> SELECT *FROM need_vacuum WHERE tablename = 'public.vac' \gx
−[ RECORD 1 ]−−−+−−−−−−−−−−−
tablename | public.vac
dead_tup | 0
max_dead_tup | 250
ins_tup | 1000
max_ins_tup | 1200
last_autovacuum |
           
     
             
      
         
             
  
=> ALTER TABLE vac SET (autovacuum_enabled = off);
=> UPDATE vac SET s = 'B' WHERE id <= 251;
=> SELECT *FROM need_vacuum WHERE tablename = 'public.vac' \gx
−[ RECORD 1 ]−−−+−−−−−−−−−−−
tablename | public.vac
dead_tup | 251
max_dead_tup | 250
ins_tup | 1000
max_ins_tup | 1200
last_autovacuum |
           
              

   
=> ALTER TABLE vac SET (autovacuum_enabled = on);
=> SELECT *FROM need_vacuum WHERE tablename = 'public.vac' \gx
−[ RECORD 1 ]−−−+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
tablename | public.vac
dead_tup | 0
max_dead_tup | 250
ins_tup | 0
max_ins_tup | 1200
last_autovacuum | 2023−03−06 14:00:51.736815+03
   
            
            

 
         
   200       
     0  
          
            
            
       
                
              
     1       
   2      
     20  
  
  

   
            
                
                 
       
 
         
              
−1
2ms
               
        
   
             
       
         
              
               
     
    
            
  
  
  
  

   
 
            
            
              
            
             
     
            
          
 
            
          
     
           
           
                
    
=> TRUNCATE vac;
=> INSERT INTO vac(id,s)
SELECT id, 'A' FROM generate_series(1,500000) id;
=> UPDATE vac SET s = 'B';
            
     
=> ALTER SYSTEM SET maintenance_work_mem = '1MB';
=> SELECT pg_reload_conf();
         
    

 
=> VACUUM VERBOSE vac;
=> SELECT *FROM pg_stat_progress_vacuum \gx
−[ RECORD 1 ]−−−−−−+−−−−−−−−−−−−−−−−−−
pid | 14531
datid | 16391
datname | internals
relid | 16479
phase | vacuuming indexes
heap_blks_total | 17242
heap_blks_scanned | 3009
heap_blks_vacuumed | 0
index_vacuum_count | 0
max_dead_tuples | 174761
num_dead_tuples | 174522
=> SELECT *FROM pg_stat_progress_vacuum \gx
−[ RECORD 1 ]−−−−−−+−−−−−−−−−−−−−−−−−−
pid | 14531
datid | 16391
datname | internals
relid | 16479
phase | vacuuming indexes
heap_blks_total | 17242
heap_blks_scanned | 17242
heap_blks_vacuumed | 6017
index_vacuum_count | 2
max_dead_tuples | 174761
num_dead_tuples | 150956
    
            
      
      
    
    
    


   
           
              
               
              
       
              
     
INFO: vacuuming "public.vac"
INFO: scanned index "vac_s" to remove 174522 row versions
DETAIL: CPU: user: 0.02 s, system: 0.00 s, elapsed: 0.05 s
INFO: table "vac": removed 174522 dead item identifiers in
3009 pages
DETAIL: CPU: user: 0.00 s, system: 0.01 s, elapsed: 0.07 s
INFO: scanned index "vac_s" to remove 174522 row versions
DETAIL: CPU: user: 0.02 s, system: 0.00 s, elapsed: 0.05 s
INFO: table "vac": removed 174522 dead item identifiers in
3009 pages
DETAIL: CPU: user: 0.00 s, system: 0.00 s, elapsed: 0.01 s
INFO: scanned index "vac_s" to remove 150956 row versions
DETAIL: CPU: user: 0.02 s, system: 0.00 s, elapsed: 0.04 s
INFO: table "vac": removed 150956 dead item identifiers in
2603 pages
DETAIL: CPU: user: 0.00 s, system: 0.00 s, elapsed: 0.00 s
INFO: index "vac_s" now contains 500000 row versions in
932 pages
DETAIL: 500000 index row versions were removed.
433 index pages were newly deleted.
433 index pages are currently deleted, of which 0 are
currently reusable.
CPU: user: 0.00 s, system: 0.00 s, elapsed: 0.00 s.
INFO: table "vac": found 500000 removable, 500000
nonremovable row versions in 17242 out of 17242 pages
DETAIL: 0 dead row versions cannot be removed yet, oldest
xmin: 851
Skipped 0 pages due to buffer pins, 0 frozen pages.
CPU: user: 0.20 s, system: 0.03 s, elapsed: 0.53 s.
VACUUM
index
vacuum
table
vacuum
index
vacuum
table
vacuum
index
vacuum
table
vacuum
             
              
               

 
         
          
               
               
 
           
             
      −1    
     
=> ALTER SYSTEM SET log_autovacuum_min_duration = 0;
=> SELECT pg_reload_conf();
=> UPDATE vac SET s = 'C';
UPDATE 500000
postgres$ tail -n 13 /home/postgres/logfile
2023−03−06 14:01:13.727 MSK [17351] LOG: automatic vacuum of table
"internals.public.vac": index scans: 3
pages: 0 removed, 17242 remain, 0 skipped due to pins, 0
skipped frozen
tuples: 500000 removed, 500000 remain, 0 are dead but not
yet removable, oldest xmin: 853
index scan needed: 8622 pages from table (50.01% of total)
had 500000 dead item identifiers removed
index "vac_s": pages: 1428 in total, 496 newly deleted, 929
currently deleted, 433 reusable
avg read rate: 12.404 MB/s, avg write rate: 14.810 MB/s
buffer usage: 46038 hits, 5670 misses, 6770 dirtied
WAL usage: 40390 records, 15062 full page images, 89188595
bytes
system usage: CPU: user: 0.31 s, system: 0.33 s, elapsed:
3.57 s
2023−03−06 14:01:14.117 MSK [17351] LOG: automatic analyze of table
"internals.public.vac"
avg read rate: 41.081 MB/s, avg write rate: 0.020 MB/s
buffer usage: 15355 hits, 2035 misses, 1 dirtied
system usage: CPU: user: 0.14 s, system: 0.00 s, elapsed:
0.38 s

   
              
           
               
         
          
             


7
Freezing
   
             
               
           
          
                
         
             
           
      
           
             
              
              
       
         
            
          
           
             
             

  

 
            
             
  
           
              
           
T1 T1
T2
T1T1
T2
T3
            
            
                 
            
       
     
           
            
               
              
               

  


     
             
           
                
           
           
T1
^
T2
T3
T4
^
^
T3
T4
T1
T1
^
^
^
T4
T1
T2
         
            
              
              
            
 
              
             
              
 
            
              
             
        
=> CREATE TABLE tfreeze(
id integer,
s char(300)
)
WITH (fillfactor = 10, autovacuum_enabled = off);

 
             
             
             
              
=> CREATE FUNCTION heap_page(
relname text, pageno_from integer, pageno_to integer
)
RETURNS TABLE(
ctid tid, state text,
xmin text, xmin_age integer, xmax text
)AS $$
SELECT (pageno,lp)::text::tid AS ctid,
CASE lp_flags
WHEN 0THEN 'unused'
WHEN 1THEN 'normal'
WHEN 2THEN 'redirect to '||lp_off
WHEN 3THEN 'dead'
END AS state,
t_xmin || CASE
WHEN (t_infomask & 256+512) = 256+512 THEN ' f'
WHEN (t_infomask & 256) > 0 THEN ' c'
WHEN (t_infomask & 512) > 0 THEN ' a'
ELSE ''
END AS xmin,
age(t_xmin) AS xmin_age,
t_xmax || CASE
WHEN (t_infomask & 1024) > 0 THEN ' c'
WHEN (t_infomask & 2048) > 0 THEN ' a'
ELSE ''
END AS xmax
FROM generate_series(pageno_from, pageno_to) p(pageno),
heap_page_items(get_raw_page(relname, pageno))
ORDER BY pageno, lp;
$$ LANGUAGE sql;
              
    
=> CREATE EXTENSION IF NOT EXISTS pg_visibility;
=> INSERT INTO tfreeze(id, s)
SELECT id, 'FOO'||id FROM generate_series(1,100) id;
INSERT 0 100

  
            
           
              
 
=> VACUUM tfreeze;
=> SELECT *
FROM generate_series(0,1) g(blkno),
pg_visibility_map('tfreeze',g.blkno)
ORDER BY g.blkno;
blkno | all_visible | all_frozen
−−−−−−−+−−−−−−−−−−−−−+−−−−−−−−−−−−
0|t |f
1|t |f
(2 rows)
             
      
=> SELECT *FROM heap_page('tfreeze',0,1);
ctid | state | xmin | xmin_age | xmax
−−−−−−−+−−−−−−−−+−−−−−−−+−−−−−−−−−−+−−−−−−
(0,1) | normal | 856 c | 1 | 0 a
(0,2) | normal | 856 c | 1 | 0 a
(1,1) | normal | 856 c | 1 | 0 a
(1,2) | normal | 856 c | 1 | 0 a
(4 rows)
  
            
        
  
    
   
   

 
  
50 million         
              
            
            

          
=> ALTER SYSTEM SET vacuum_freeze_min_age = 1;
=> SELECT pg_reload_conf();
                
       
=> UPDATE tfreeze SET s = 'BAR' WHERE id = 1;
               
 
=> SELECT *FROM heap_page('tfreeze',0,1);
ctid | state | xmin | xmin_age | xmax
−−−−−−−+−−−−−−−−+−−−−−−−+−−−−−−−−−−+−−−−−−
(0,1) | normal | 856 c | 2 | 857
(0,2) | normal | 856 c | 2 | 0 a
(0,3) | normal | 857 | 1 | 0 a
(1,1) | normal | 856 c | 2 | 0 a
(1,2) | normal | 856 c | 2 | 0 a
(5 rows)
          
              
=> SELECT *FROM generate_series(0,1) g(blkno),
pg_visibility_map('tfreeze',g.blkno)
ORDER BY g.blkno;
blkno | all_visible | all_frozen
−−−−−−−+−−−−−−−−−−−−−+−−−−−−−−−−−−
0|f |f
1|t |f
(2 rows)

  
             
                
    
=> VACUUM tfreeze;
=> SELECT *FROM heap_page('tfreeze',0,1);
ctid | state | xmin | xmin_age | xmax
−−−−−−−+−−−−−−−−−−−−−−−+−−−−−−−+−−−−−−−−−−+−−−−−−
(0,1) | redirect to 3 | | |
(0,2) | normal | 856 f | 2 | 0 a
(0,3) | normal | 857 c | 1 | 0 a
(1,1) | normal | 856 c | 2 | 0 a
(1,2) | normal | 856 c | 2 | 0 a
(5 rows)
              
        
=> SELECT *FROM generate_series(0,1) g(blkno),
pg_visibility_map('tfreeze',g.blkno)
ORDER BY g.blkno;
blkno | all_visible | all_frozen
−−−−−−−+−−−−−−−−−−−−−+−−−−−−−−−−−−
0|t |f
1|t |f
(2 rows)
   
               
          
   150
million
     
              

              
             

 
=> SELECT relfrozenxid, age(relfrozenxid)
FROM pg_class
WHERE relname = 'tfreeze';
relfrozenxid | age
−−−−−−−−−−−−−−+−−−−−
854 | 4
(1 row)
            
          
                
               
           
                
         
           
         
           
           
       
          
        
=> ALTER SYSTEM SET vacuum_freeze_table_age = 4;
=> SELECT pg_reload_conf();
   
=> VACUUM VERBOSE tfreeze;
INFO: aggressively vacuuming "public.tfreeze"
INFO: table "tfreeze": found 0 removable, 100 nonremovable row
versions in 50 out of 50 pages
DETAIL: 0 dead row versions cannot be removed yet, oldest xmin: 858
Skipped 0 pages due to buffer pins, 0 frozen pages.
CPU: user: 0.00 s, system: 0.00 s, elapsed: 0.00 s.
VACUUM

  
             
          
=> SELECT relfrozenxid, age(relfrozenxid)
FROM pg_class
WHERE relname = 'tfreeze';
relfrozenxid | age
−−−−−−−−−−−−−−+−−−−−
857 | 1
(1 row)
       
=> SELECT *FROM heap_page('tfreeze',0,1);
ctid | state | xmin | xmin_age | xmax
−−−−−−−+−−−−−−−−−−−−−−−+−−−−−−−+−−−−−−−−−−+−−−−−−
(0,1) | redirect to 3 | | |
(0,2) | normal | 856 f | 2 | 0 a
(0,3) | normal | 857 c | 1 | 0 a
(1,1) | normal | 856 f | 2 | 0 a
(1,2) | normal | 856 f | 2 | 0 a
(5 rows)
        
=> SELECT *FROM generate_series(0,1) g(blkno),
pg_visibility_map('tfreeze',g.blkno)
ORDER BY g.blkno;
blkno | all_visible | all_frozen
−−−−−−−+−−−−−−−−−−−−−+−−−−−−−−−−−−
0|t |f
1|t |t
(2 rows)
   
            
           
               

 
           
         
             
           200
million

            
           
              
=> SELECT datname, datfrozenxid, age(datfrozenxid) FROM pg_database;
datname | datfrozenxid | age
−−−−−−−−−−−+−−−−−−−−−−−−−−+−−−−−
postgres | 726 | 132
template1 | 726 | 132
template0 | 726 | 132
internals | 726 | 132
(4 rows)
xid


of table 1

of table 3

of table 2
all row versions
in the database are
guaranteed to be frozen
           
                
           
               
            

  

  
            
             
               
        
      
             
            
   
  
  
  
    
            
           
      
        
             
       1.6 billion    
       
  
            

  
  

 
  
            
              
 
                 
                
          
           
                
     
     
                
              

              
           
             
             
           
              
   
           
         
=> BEGIN ISOLATION LEVEL REPEATABLE READ;
=> SELECT 1;
-- the snapshot is built
              
           
    

  
=> BEGIN;
=> TRUNCATE tfreeze;
=> COPY tfreeze FROM stdin WITH FREEZE;
1 FOO
2 BAR
3 BAZ
\.
=> COMMIT;
         
=> SELECT count(*) FROM tfreeze;
count
−−−−−−−
3
(1 row)
=> COMMIT;
             
       
                 
      
=> SELECT *FROM pg_visibility_map('tfreeze',0);
all_visible | all_frozen
−−−−−−−−−−−−−+−−−−−−−−−−−−
t | t
(1 row)
=> SELECT flags & 4 > 0 AS all_visible
FROM page_header(get_raw_page('tfreeze',0));
all_visible
−−−−−−−−−−−−−
t
(1 row)
               
          
              
              

8
Rebuilding Tables and Indexes
  
     
            
   
               
              
              
        
       
       
            
 
          
         
              
          
                
           


  
           
               
             
              
    
  
           
=> TRUNCATE vac;
=> INSERT INTO vac(id,s)
SELECT id, id::text FROM generate_series(1,500000) id;
        
=> CREATE EXTENSION pgstattuple;
=> SELECT *FROM pgstattuple('vac') \gx
−[ RECORD 1 ]−−−−−−+−−−−−−−−−
table_len | 70623232
tuple_count | 500000
tuple_len | 64500000
tuple_percent | 91.33
dead_tuple_count | 0
dead_tuple_len | 0
dead_tuple_percent | 0
free_space | 381844
free_percent | 0.54
            
            
             
           
          
              


    
=> SELECT *FROM pgstatindex('vac_s') \gx
−[ RECORD 1 ]−−−−−−+−−−−−−−−−−
version | 4
tree_level | 3
index_size | 114302976
root_block_no | 2825
internal_pages | 376
leaf_pages | 13576
empty_pages | 0
deleted_pages | 0
avg_leaf_density | 53.88
leaf_fragmentation | 10.59
              
              
        
          
             
         
          
=> SELECT pg_size_pretty(pg_table_size('vac')) AS table_size,
pg_size_pretty(pg_indexes_size('vac')) AS index_size;
table_size | index_size
−−−−−−−−−−−−+−−−−−−−−−−−−
67 MB | 109 MB
(1 row)
       
=> DELETE FROM vac WHERE id % 10 != 0;
DELETE 450000
             
     
=> VACUUM vac;


  
=> SELECT pg_size_pretty(pg_table_size('vac')) AS table_size,
pg_size_pretty(pg_indexes_size('vac')) AS index_size;
table_size | index_size
−−−−−−−−−−−−+−−−−−−−−−−−−
67 MB | 109 MB
(1 row)
       
=> SELECT vac.tuple_percent, vac_s.avg_leaf_density
FROM pgstattuple('vac') vac, pgstatindex('vac_s') vac_s;
tuple_percent | avg_leaf_density
−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−−−
9.13 | 6.71
(1 row)
           
=> SELECT pg_relation_filepath('vac') AS vac_filepath,
pg_relation_filepath('vac_s') AS vac_s_filepath \gx
−[ RECORD 1 ]−−+−−−−−−−−−−−−−−−−−
vac_filepath | base/16391/16514
vac_s_filepath | base/16391/16515
              
            
    
=> VACUUM FULL vac;
=> SELECT *FROM pg_stat_progress_cluster \gx
−[ RECORD 1 ]−−−−−−−+−−−−−−−−−−−−−−−−−
pid | 19488
datid | 16391
datname | internals
relid | 16479
command | VACUUM FULL
phase | rebuilding index
cluster_index_relid | 0
heap_tuples_scanned | 50000
heap_tuples_written | 50000
heap_blks_total | 8621
heap_blks_scanned | 8621
index_rebuild_count | 0

    
        
        
=> SELECT pg_relation_filepath('vac') AS vac_filepath,
pg_relation_filepath('vac_s') AS vac_s_filepath \gx
−[ RECORD 1 ]−−+−−−−−−−−−−−−−−−−−
vac_filepath | base/16391/16526
vac_s_filepath | base/16391/16529
        
=> SELECT pg_size_pretty(pg_table_size('vac')) AS table_size,
pg_size_pretty(pg_indexes_size('vac')) AS index_size;
table_size | index_size
−−−−−−−−−−−−+−−−−−−−−−−−−
6904 kB | 6504 kB
(1 row)
              
              
            
=> SELECT vac.tuple_percent,
vac_s.avg_leaf_density
FROM pgstattuple('vac') vac,
pgstatindex('vac_s') vac_s;
tuple_percent | avg_leaf_density
−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−−−
91.23 | 91.08
(1 row)

            
          


  
=> SELECT *FROM heap_page('vac',0,0) LIMIT 5;
ctid | state | xmin | xmin_age | xmax
−−−−−−−+−−−−−−−−+−−−−−−−+−−−−−−−−−−+−−−−−−
(0,1) | normal | 861 f | 5 | 0 a
(0,2) | normal | 861 f | 5 | 0 a
(0,3) | normal | 861 f | 5 | 0 a
(0,4) | normal | 861 f | 5 | 0 a
(0,5) | normal | 861 f | 5 | 0 a
(5 rows)
               
             
        
=> SELECT *FROM pg_visibility_map('vac',0);
all_visible | all_frozen
−−−−−−−−−−−−−+−−−−−−−−−−−−
f | f
(1 row)
=> SELECT flags & 4 > 0 all_visible
FROM page_header(get_raw_page('vac',0));
all_visible
−−−−−−−−−−−−−
f
(1 row)
           
=> VACUUM vac;
=> SELECT *FROM pg_visibility_map('vac',0);
all_visible | all_frozen
−−−−−−−−−−−−−+−−−−−−−−−−−−
t | t
(1 row)
=> SELECT flags & 4 > 0 AS all_visible
FROM page_header(get_raw_page('vac',0));
all_visible
−−−−−−−−−−−−−
t
(1 row)

    
              
        
   
   
             
              
    
              
                
             
             

          
      
           
         
           
              
             
 
   
                
              
   


  

 
            
              
               
           
              
             

         
              
        
           
              
              
            
    
 
 
           
        
           
             
            
           
  
             
            
      



    
        
             
           
  
         
        
 
           
              
             
   
             
=> ALTER TABLE vac ADD processed boolean DEFAULT false;
=> SELECT pg_size_pretty(pg_table_size('vac'));
pg_size_pretty
−−−−−−−−−−−−−−−−
6936 kB
(1 row)
            
=> UPDATE vac SET processed = true;
UPDATE 50000
=> SELECT pg_size_pretty(pg_table_size('vac'));
pg_size_pretty
−−−−−−−−−−−−−−−−
14 MB
(1 row)
          
           
             
             
            

 
SELECT ID
FROM table
WHERE filtering the already processed rows
LIMIT batch size
FOR UPDATE SKIP LOCKED
             
             
                
             
            
        
=> UPDATE vac SET processed = false;
=> VACUUM FULL vac;
          
=> WITH batch AS (
SELECT id FROM vac WHERE NOT processed LIMIT 1000
FOR UPDATE SKIP LOCKED
)
UPDATE vac SET processed = true
WHERE id IN (SELECT id FROM batch);
UPDATE 1000
=> SELECT pg_size_pretty(pg_table_size('vac'));
pg_size_pretty
−−−−−−−−−−−−−−−−
7064 kB
(1 row)
              
 
=> VACUUM vac;
=> WITH batch AS (
SELECT id FROM vac WHERE NOT processed LIMIT 1000
FOR UPDATE SKIP LOCKED
)
UPDATE vac SET processed = true
WHERE id IN (SELECT id FROM batch);
UPDATE 1000

    
=> SELECT pg_size_pretty(pg_table_size('vac'));
pg_size_pretty
−−−−−−−−−−−−−−−−
7072 kB
(1 row)

Part II
Buffer Cache
and WAL
9
Buffer Cache
 
          
               
         
             
           
           
              
            
           

          
    
             
           
            
            
               
            
             
            
             


  
            
            
         
            
      
   
              
               
         
               
          
     
                 
          
    
header
page
buffer cache
             
             
             
             
  
    



   
            
              
                
              
             
              
        
=> CREATE EXTENSION pg_buffercache;
     
=> CREATE TABLE cacheme(
id integer
)WITH (autovacuum_enabled = off);
=> INSERT INTO cacheme VALUES (1);
             
             
         
=> CREATE FUNCTION buffercache(rel regclass)
RETURNS TABLE(
bufferid integer, relfork text, relblk bigint,
isdirty boolean, usagecount smallint, pins integer
)AS $$
SELECT bufferid,
CASE relforknumber
WHEN 0THEN 'main'
WHEN 1THEN 'fsm'
WHEN 2THEN 'vm'
END,
relblocknumber,
isdirty,
usagecount,
pinning_backends
FROM pg_buffercache
WHERE relfilenode = pg_relation_filenode(rel)
ORDER BY relforknumber, relblocknumber;
$$ LANGUAGE sql;


  
=> SELECT *FROM buffercache('cacheme');
bufferid | relfork | relblk | isdirty | usagecount | pins
−−−−−−−−−−+−−−−−−−−−+−−−−−−−−+−−−−−−−−−+−−−−−−−−−−−−+−−−−−−
268 | main | 0 | t | 1 | 0
(1 row)
                
    
  
            
              
             
            
                  
      
               
               
                
            
             
               
               
                
            
           
                 
             
              

  



  
3501, 0, 3
2610, 0, 7
hash table
             
                
             
           
  
              
               
    
            
              
                
            
        
            
         
  

  
=> EXPLAIN (analyze, buffers, costs off, timing off, summary off)
SELECT *FROM cacheme;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Seq Scan on cacheme (actual rows=1 loops=1)
Buffers: shared hit=1
Planning:
Buffers: shared hit=12 read=7
(4 rows)
                
      
=> SELECT *FROM buffercache('cacheme');
bufferid | relfork | relblk | isdirty | usagecount | pins
−−−−−−−−−−+−−−−−−−−−+−−−−−−−−+−−−−−−−−−+−−−−−−−−−−−−+−−−−−−
268 | main | 0 | t | 2 | 0
(1 row)
          
                 

=> BEGIN;
=> DECLARE cCURSOR FOR SELECT *FROM cacheme;
=> FETCH c;
id
−−−−
1
(1 row)
=> SELECT *FROM buffercache('cacheme');
bufferid | relfork | relblk | isdirty | usagecount | pins
−−−−−−−−−−+−−−−−−−−−+−−−−−−−−+−−−−−−−−−+−−−−−−−−−−−−+−−−−−−
268 | main | 0 | t | 3 | 1
(1 row)
             
       

  
=> VACUUM VERBOSE cacheme;
INFO: vacuuming "public.cacheme"
INFO: table "cacheme": found 0 removable, 0 nonremovable row
versions in 1 out of 1 pages
DETAIL: 0 dead row versions cannot be removed yet, oldest xmin:
877
Skipped 1 page due to buffer pins, 0 frozen pages.
CPU: user: 0.00 s, system: 0.00 s, elapsed: 0.00 s.
VACUUM
             
 
                
             
  
              
         
=> COMMIT;
=> SELECT *FROM buffercache('cacheme');
bufferid | relfork | relblk | isdirty | usagecount | pins
−−−−−−−−−−+−−−−−−−−−+−−−−−−−−+−−−−−−−−−+−−−−−−−−−−−−+−−−−−−
268 | main | 0 | t | 3 | 0
310 | vm | 0 | f | 2 | 0
(2 rows)
         
             
=> INSERT INTO cacheme VALUES (2);
=> SELECT *FROM buffercache('cacheme');
bufferid | relfork | relblk | isdirty | usagecount | pins
−−−−−−−−−−+−−−−−−−−−+−−−−−−−−+−−−−−−−−−+−−−−−−−−−−−−+−−−−−−
268 | main | 0 | t | 4 | 0
310 | vm | 0 | f | 2 | 0
(2 rows)
  

  
           
            
 
  
                
             
             
        
postgres$ pg_ctl restart -l /home/postgres/logfile
               
  
=> EXPLAIN (analyze, buffers, costs off, timing off, summary off)
SELECT *FROM cacheme;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Seq Scan on cacheme (actual rows=2 loops=1)
Buffers: shared read=1 dirtied=1
Planning:
Buffers: shared hit=15 read=7
(4 rows)
             
              
               

=> SELECT *FROM buffercache('cacheme');
bufferid | relfork | relblk | isdirty | usagecount | pins
−−−−−−−−−−+−−−−−−−−−+−−−−−−−−+−−−−−−−−−+−−−−−−−−−−−−+−−−−−−
98 | main | 0 | t | 1 | 0
(1 row)

  
          
 
=> SELECT heap_blks_read, heap_blks_hit
FROM pg_statio_all_tables
WHERE relname = 'cacheme';
heap_blks_read | heap_blks_hit
−−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−
2 | 5
(1 row)
           
       off  
   
           
               
              
         
            
            
       
                
           
               
             
             
            
              
          
  
  

  
             
            
             
         
              
             
          
 
                
       
                
             
free buffers
clock hand
             
                 
                

  
               
              
              
                
         
                
              
             
  
              
      
            
       
              
            
             
              
             
             
        
              
                
               
  
    
               
            
  

  
             
            
              
              
            
         
              
            
           
             
      
      

           
            
       
            
             
           

            
              
         
             
               
               
      
=> CREATE TABLE big(
id integer PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
s char(1000)
)WITH (fillfactor = 10);


  
=> INSERT INTO big(s)
SELECT 'FOO' FROM generate_series(1,4096+1);
   
=> ANALYZE big;
=> SELECT relname, relfilenode, relpages
FROM pg_class
WHERE relname IN ('big', 'big_pkey');
relname | relfilenode | relpages
−−−−−−−−−−+−−−−−−−−−−−−−+−−−−−−−−−−
big | 16546 | 4097
big_pkey | 16551 | 14
(2 rows)
               
   
postgres$ pg_ctl restart -l /home/postgres/logfile
         
=> EXPLAIN (analyze, costs off, timing off, summary off)
SELECT id FROM big;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Seq Scan on big (actual rows=4097 loops=1)
(1 row)
              
=> SELECT count(*)
FROM pg_buffercache
WHERE relfilenode = pg_relation_filenode('big'::regclass);
count
−−−−−−−
32
(1 row)
             

  
=> EXPLAIN (analyze, costs off, timing off, summary off)
SELECT *FROM big ORDER BY id;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Index Scan using big_pkey on big (actual rows=4097 loops=1)
(1 row)
             

=> SELECT relfilenode, count(*)
FROM pg_buffercache
WHERE relfilenode IN (
pg_relation_filenode('big'),
pg_relation_filenode('big_pkey')
)
GROUP BY relfilenode;
relfilenode | count
−−−−−−−−−−−−−+−−−−−−−
16546 | 4097
16551 | 14
(2 rows)
     
        128MB    
                
             
       
       
              
                
             
               
             
          

     
             
             
            
             
             
             
            
    
     
       

            
          
              
 
           
      
=> SELECT usagecount, count(*)
FROM pg_buffercache
GROUP BY usagecount
ORDER BY usagecount;
usagecount | count
−−−−−−−−−−−−+−−−−−−−
1 | 4128
2 | 50
3 | 4
4 | 4
5 | 73
| 12125
(6 rows)
            
              
             
          
              
             

  
=> SELECT c.relname,
count(*) blocks,
round( 100.0 * 8192 * count(*) /
pg_table_size(c.oid) ) AS "% of rel",
round( 100.0 * 8192 * count(*) FILTER (WHERE b.usagecount > 1) /
pg_table_size(c.oid) ) AS "% hot"
FROM pg_buffercache b
JOIN pg_class c ON pg_relation_filenode(c.oid) = b.relfilenode
WHERE b.reldatabase IN (
0,
-- cluster-wide objects
(SELECT oid FROM pg_database WHERE datname = current_database())
)
AND b.usagecount IS NOT NULL
GROUP BY c.relname, c.oid
ORDER BY 2DESC
LIMIT 10;
relname | blocks | % of rel | % hot
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+−−−−−−−−+−−−−−−−−−−+−−−−−−−
big | 4097 | 100 | 1
pg_attribute | 30 | 48 | 47
big_pkey | 14 | 100 | 0
pg_proc | 13 | 12 | 6
pg_operator | 11 | 61 | 50
pg_class | 10 | 59 | 59
pg_proc_oid_index | 9 | 82 | 45
pg_attribute_relid_attnum_index | 8 | 73 | 64
pg_proc_proname_args_nsp_index | 6 | 18 | 6
pg_amproc | 5 | 56 | 56
(10 rows)
               
    
           
          
            

          
      

  
  
              
              
       
=> CREATE EXTENSION pg_prewarm;
              
              
           
     
=> ALTER SYSTEM SET shared_preload_libraries = 'pg_prewarm';
postgres$ pg_ctl restart -l /home/postgres/logfile
  on       
            
300s         
        
postgres$ ps -o pid,command \
--ppid `head -n 1 /usr/local/pgsql/data/postmaster.pid` | \
grep prewarm
23124 postgres: autoprewarm leader
             
=> SELECT count(*)
FROM pg_buffercache
WHERE relfilenode = pg_relation_filenode('big'::regclass);
count
−−−−−−−
0
(1 row)

  
             
             
      
=> SELECT pg_prewarm('big');
pg_prewarm
−−−−−−−−−−−−
4097
(1 row)
=> SELECT count(*)
FROM pg_buffercache
WHERE relfilenode = pg_relation_filenode('big'::regclass);
count
−−−−−−−
4097
(1 row)
            
             
 
=> SELECT autoprewarm_dump_now();
autoprewarm_dump_now
−−−−−−−−−−−−−−−−−−−−−−
4224
(1 row)
              
               
           
postgres$ head -n 10 /usr/local/pgsql/data/autoprewarm.blocks
<<4224>>
0,1664,1262,0,0
0,1664,1260,0,0
16391,1663,1259,0,0
16391,1663,1259,0,1
16391,1663,1259,0,2
16391,1663,1259,0,3
16391,1663,1249,0,0
16391,1663,1249,0,1
16391,1663,1249,0,2

  
    
postgres$ pg_ctl restart -l /home/postgres/logfile
       
=> SELECT count(*)
FROM pg_buffercache
WHERE relfilenode = pg_relation_filenode('big'::regclass);
count
−−−−−−−
4097
(1 row)
              
             
            
  
          
                
            
  
          
      
           
      
           
            
               



  
            
             
  8MB  
           
               
 
              
   
=> CREATE TEMPORARY TABLE tmp AS SELECT 1;
=> EXPLAIN (analyze, buffers, costs off, timing off, summary off)
SELECT *FROM tmp;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Seq Scan on tmp (actual rows=1 loops=1)
Buffers: local hit=1
Planning:
Buffers: shared hit=12 read=7
(4 rows)

10
Write-Ahead Log
 
              
               
              
           
              
              
            
            
         
          
               
           
            
             
            
          
             
             
           
            
              


   
           
           
           
             
           
         
         
         
           
            

     
   
          
   
             
      
            
  
  
 
           
           



  
         
 
     
      
     
 
     
               

             
               
          
           
   
              
        −1      
  
      
               
               
              
   
              
              
=> SELECT pg_current_wal_lsn(), pg_current_wal_insert_lsn();
pg_current_wal_lsn | pg_current_wal_insert_lsn
−−−−−−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−−−−−
0/3DF56000 | 0/3DF57968
(1 row)



   
             
           
             
              
  
  
=> CREATE TABLE wal(id integer);
=> INSERT INTO wal VALUES (1);
          
=> BEGIN;
=> SELECT pg_current_wal_insert_lsn();
pg_current_wal_insert_lsn
−−−−−−−−−−−−−−−−−−−−−−−−−−−
0/3DF708D8
(1 row)
        
=> UPDATE wal SET id = id + 1;
             
             
=> SELECT pg_current_wal_insert_lsn();
pg_current_wal_insert_lsn
−−−−−−−−−−−−−−−−−−−−−−−−−−−
0/3DF70920
(1 row)
             
              
         
=> SELECT lsn FROM page_header(get_raw_page('wal',0));
lsn
−−−−−−−−−−−−
0/3DF70920
(1 row)

  
             
                 
          
              
    
=> COMMIT;
           
=> SELECT pg_current_wal_insert_lsn();
pg_current_wal_insert_lsn
−−−−−−−−−−−−−−−−−−−−−−−−−−−
0/3DF70948
(1 row)
              
           
             
                 
         
                 
                
          
              
            
      
=> SELECT '0/3DF70948'::pg_lsn - '0/3DF708D8'::pg_lsn;
?column?
−−−−−−−−−−
112
(1 row)

  
  

   
            
   
             
             
 
 
              
      16MB  
              
            
  
              
  
              
   
=> SELECT file_name, upper(to_hex(file_offset)) file_offset
FROM pg_walfile_name_offset('0/3DF708D8');
file_name | file_offset
−−−−−−−−−−−−−−−−−−−−−−−−−−+−−−−−−−−−−−−−
00000001000000000000003D | F708D8
(1 row)
timeline log sequence number
             
            
            
           
=> SELECT *
FROM pg_ls_waldir()
WHERE name = '00000001000000000000003D';

 
name | size | modification
−−−−−−−−−−−−−−−−−−−−−−−−−−+−−−−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−−
00000001000000000000003D | 16777216 | 2023−03−06 14:01:48+03
(1 row)
              
              
    
              
      
postgres$ /usr/local/pgsql/bin/pg_waldump \
-p /usr/local/pgsql/data/pg_wal -s 0/3DF708D8 -e 0/3DF70948
#
rmgr: Heap len (rec/tot): 69/ 69, tx: 886, lsn:
0/3DF708D8, prev 0/3DF708B0, desc: HOT_UPDATE off 1 xmax 886 flags
0x40 ; new off 2 xmax 0, blkref #0: rel 1663/16391/16562 blk 0
rmgr: Transaction len (rec/tot): 34/ 34, tx: 886, lsn:
0/3DF70920, prev 0/3DF708D8, desc: COMMIT 2023−03−06 14:01:48.875861
MSK
        
             
              
=> SELECT pg_relation_filepath('wal');
pg_relation_filepath
−−−−−−−−−−−−−−−−−−−−−−
base/16391/16562
(1 row)
           

 
          
              
             

   
                 
               
              
           
              
          
               
 
          
              
            
            
        

           
      
   
           
   
                
           
            
             
      
               
         
         

  
  

 
              
              
      
            
            
 
             
          
              
            
  
time
checkpoint
failure
start of
recovery
required WAL les
time
checkpoint checkpoint
failure
start of
recovery
required WAL les
         
         
             
           
          


   
checkpoint
start
CHECKPOINT
checkpoint
nish
Latest checkpoint location: 0/3E7EF818
Latest checkpoint's REDO location: 0/3E7EF7E0
PGDATA/global/pg_control
              
      
=> UPDATE big SET s = 'FOO';
=> SELECT count(*) FROM pg_buffercache WHERE isdirty;
count
−−−−−−−
4119
(1 row)
    
=> SELECT pg_current_wal_insert_lsn();
pg_current_wal_insert_lsn
−−−−−−−−−−−−−−−−−−−−−−−−−−−
0/3E7EF7E0
(1 row)
             
            
=> CHECKPOINT;
=> SELECT count(*) FROM pg_buffercache WHERE isdirty;
count
−−−−−−−
0
(1 row)
         

 
=> SELECT pg_current_wal_insert_lsn();
pg_current_wal_insert_lsn
−−−−−−−−−−−−−−−−−−−−−−−−−−−
0/3E7EF890
(1 row)
postgres$ /usr/local/pgsql/bin/pg_waldump \
-p /usr/local/pgsql/data/pg_wal -s 0/3E7EF7E0 -e 0/3E7EF890
rmgr: Standby len (rec/tot): 50/ 50, tx: 0, lsn:
0/3E7EF7E0, prev 0/3E7EF7B8, desc: RUNNING_XACTS nextXid 888
latestCompletedXid 887 oldestRunningXid 888
rmgr: XLOG len (rec/tot): 114/ 114, tx: 0, lsn:
0/3E7EF818, prev 0/3E7EF7E0, desc: CHECKPOINT_ONLINE redo
0/3E7EF7E0; tli 1; prev tli 1; fpw true; xid 0:888; oid 24754; multi
1; offset 0; oldest xid 726 in DB 1; oldest multi 1 in DB 1;
oldest/newest commit timestamp xid: 0/0; oldest running xid 888;
online
          
              
             
          
postgres$ /usr/local/pgsql/bin/pg_controldata \
-D /usr/local/pgsql/data | egrep 'Latest.*location'
Latest checkpoint location: 0/3E7EF818
Latest checkpoint's REDO location: 0/3E7EF7E0
 
             
            
          
             
   

  

   
postgres$ /usr/local/pgsql/bin/pg_controldata \
-D /usr/local/pgsql/data | grep state
Database cluster state: in production
           
            
           
     
            
     
             
                 
               
              

             
                
          
          
             
              
              
  
             
                
            
   
           
        
             
             
             

 
              
           
               
     
            
postgres$ pg_ctl stop -m immediate
     
postgres$ /usr/local/pgsql/bin/pg_controldata \
-D /usr/local/pgsql/data | grep 'state'
Database cluster state: in production
             
   
postgres$ pg_ctl start -l /home/postgres/logfile
postgres$ tail -n 6 /home/postgres/logfile
LOG: database system was interrupted; last known up at 2023−03−06
14:01:49 MSK
LOG: database system was not properly shut down; automatic recovery
in progress
LOG: redo starts at 0/3E7EF7E0
LOG: invalid record length at 0/3E7EF890: wanted 24, got 0
LOG: redo done at 0/3E7EF818 system usage: CPU: user: 0.00 s,
system: 0.00 s, elapsed: 0.00 s
LOG: database system is ready to accept connections
            
          
    
=> SELECT pg_current_wal_insert_lsn();
pg_current_wal_insert_lsn
−−−−−−−−−−−−−−−−−−−−−−−−−−−
0/3E7EF908
(1 row)
  

   
     
postgres$ pg_ctl stop
     
postgres$ /usr/local/pgsql/bin/pg_controldata \
-D /usr/local/pgsql/data | grep state
Database cluster state: shut down
            
  
postgres$ /usr/local/pgsql/bin/pg_waldump \
-p /usr/local/pgsql/data/pg_wal -s 0/3E7EF908
rmgr: XLOG len (rec/tot): 114/ 114, tx: 0, lsn:
0/3E7EF908, prev 0/3E7EF890, desc: CHECKPOINT_SHUTDOWN redo
0/3E7EF908; tli 1; prev tli 1; fpw true; xid 0:888; oid 24754; multi
1; offset 0; oldest xid 726 in DB 1; oldest multi 1 in DB 1;
oldest/newest commit timestamp xid: 0/0; oldest running xid 0;
shutdown
pg_waldump: fatal: error in WAL record at 0/3E7EF908: invalid record
length at 0/3E7EF980: wanted 24, got 0
              
    
postgres$ pg_ctl start -l /home/postgres/logfile
  
                
             
     
            

  
       
            
    
             
    
           
                
            
      
           
  
 
             
     0.9    
             
             
               
           
   
           
            
            
            
            
             
     


   
            
    5min        
             
             
               
             
           1GB  
          
              
              
          

              
  
           
          
       
         
            
 
              
          
  
              
         
 
             
                
   
  

  
           
        
             
        80MB   
      
          
          on     
 
              
 
time
WAL size
checkpoint_timeout
max_wal_size
the size of WAL generated between
the starts of two checkpoints
                 
  
         
           
                
          
       
  
  

   
             
0MB  
  
           
             
   
        200ms 
  
            
           
              
        2
              
100  
             
             
  

          
            
30s        
        
off      
       
=> ALTER SYSTEM SET log_checkpoints = on;
=> SELECT pg_reload_conf();
        

  
=> UPDATE big SET s = 'BAR';
=> CHECKPOINT;
             
            
       
postgres$ tail -n 2 /home/postgres/logfile
LOG: checkpoint starting: immediate force wait
LOG: checkpoint complete: wrote 4100 buffers (25.0%); 0 WAL file(s)
added, 1 removed, 0 recycled; write=0.076 s, sync=0.009 s,
total=0.099 s; sync files=3, longest=0.007 s, average=0.003 s;
distance=9213 kB, estimate=9213 kB
            
        

            
        
=> SELECT *FROM pg_stat_bgwriter \gx
−[ RECORD 1 ]−−−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
checkpoints_timed | 0
checkpoints_req | 14
checkpoint_write_time | 33111
checkpoint_sync_time | 221
buffers_checkpoint | 14253
buffers_clean | 13066
maxwritten_clean | 122
buffers_backend | 84226
buffers_backend_fsync | 0
buffers_alloc | 86700
stats_reset | 2023−03−06 14:00:07.369124+03
          
        
     
        
      

   
        
      
            
   
   
    
         
      
          
             
  
       
=> SELECT pg_stat_reset_shared('bgwriter');

11
WAL Modes
 
             
            
               
             
           
  
              
               
           
                
                
          
         
        
         
        
       on 



   
            
             
       
             
   
           
          0s  
          5 
           
               
          
             
          
         
           
             
            
          
         
    
           
            
     
         
 
            
           
  200ms  
  
  



 
            
             
          
     
             
         
  
            
              
              
                
              
            
      1MB  
            
          
             
        
    
            
           
               
              
       
            
   
           
            
            
       
  

   
           
          
    
postgres$ /usr/local/pgsql/bin/pgbench -i internals
      
postgres$ /usr/local/pgsql/bin/pgbench -T 30 internals
pgbench (14.7)
starting vacuum...end.
transaction type: <builtin: TPC−B (sort of)>
scaling factor: 1
query mode: simple
number of clients: 1
number of threads: 1
duration: 30 s
number of transactions actually processed: 20123
latency average = 1.491 ms
initial connection time = 2.507 ms
tps = 670.809688 (without initial connection time)
         
=> ALTER SYSTEM SET synchronous_commit = off;
=> SELECT pg_reload_conf();
postgres$ /usr/local/pgsql/bin/pgbench -T 30 internals
pgbench (14.7)
starting vacuum...end.
transaction type: <builtin: TPC−B (sort of)>
scaling factor: 1
query mode: simple
number of clients: 1
number of threads: 1
duration: 30 s
number of transactions actually processed: 61809
latency average = 0.485 ms
initial connection time = 1.915 ms
tps = 2060.399861 (without initial connection time)


  
          
           
               
     
    
=> ALTER SYSTEM RESET synchronous_commit;
=> SELECT pg_reload_conf();
  
          
           
            
      

           
 
             
               
            
 
             
             
            
        
            
              


   
             
           
        
            
                
            
            
     
            
       
          
             
         
            
              
 
            
             
         
        
             
            
                
 
            
          on 
            
          
        
  

  

  
 
            
              
        
           
             
          
          
          
       
           
              
        
             
      
            
        
           
  
=> SHOW data_checksums;
data_checksums
−−−−−−−−−−−−−−−−
on
(1 row)
                 
 




   
=> SELECT pg_relation_filepath('wal');
pg_relation_filepath
−−−−−−−−−−−−−−−−−−−−−−
base/16391/16562
(1 row)
postgres$ pg_ctl stop
postgres$ dd if=/dev/zero of=/usr/local/pgsql/data/base/16391/16562 \
oflag=dsync conv=notrunc bs=1 count=8
8+0 records in
8+0 records out
8 bytes copied, 0,00776573 s, 1,0 kB/s
   
postgres$ pg_ctl start -l /home/postgres/logfile
              
             
       
      
=> SELECT *FROM wal LIMIT 1;
WARNING: page verification failed, calculated checksum 20397 but
expected 28733
ERROR: invalid page in block 0 of relation base/16391/16562
                
             
 off  
=> SET ignore_checksum_failure = on;
=> SELECT *FROM wal LIMIT 1;
WARNING: page verification failed, calculated checksum 20397 but
expected 28733
id
−−−−
2
(1 row)
            
             

  
 
             
             
              
     
             
              
  on          

              
               
            
         
                
            
             
      off      
   
           
            
        off 
          
          

=> CHECKPOINT;
=> SELECT pg_current_wal_insert_lsn();
pg_current_wal_insert_lsn
−−−−−−−−−−−−−−−−−−−−−−−−−−−
0/42CE5DA8
(1 row)
  
  

   
postgres$ /usr/local/pgsql/bin/pgbench -t 20000 internals
=> SELECT pg_current_wal_insert_lsn();
pg_current_wal_insert_lsn
−−−−−−−−−−−−−−−−−−−−−−−−−−−
0/449113E0
(1 row)
        
=> SELECT pg_size_pretty('0/449755C0'::pg_lsn - '0/42CE5DA8'::pg_lsn);
pg_size_pretty
−−−−−−−−−−−−−−−−
29 MB
(1 row)
                 
              
             
postgres$ /usr/local/pgsql/bin/pg_waldump --stats \
-p /usr/local/pgsql/data/pg_wal -s 0/42CE5DA8 -e 0/449755C0
Type N (%) Record size (%) FPI size (%)
−−−− −−− −−−−−−−−−−− −−− −−−−−−−− −−−
XLOG 4294 ( 3,31) 210406 ( 2,50) 19820068 ( 93,78)
Transaction 20004 ( 15,41) 680536 ( 8,10) 0 ( 0,00)
Storage 1 ( 0,00) 42 ( 0,00) 0 ( 0,00)
CLOG 1 ( 0,00) 30 ( 0,00) 0 ( 0,00)
Standby 6 ( 0,00) 416 ( 0,00) 0 ( 0,00)
Heap2 24774 ( 19,09) 1536253 ( 18,27) 24576 ( 0,12)
Heap 80234 ( 61,81) 5946242 ( 70,73) 295664 ( 1,40)
Btree 494 ( 0,38) 32747 ( 0,39) 993860 ( 4,70)
−−−−−− −−−−−−−− −−−−−−−−
Total 129808 8406672 [28,46%] 21134168 [71,54%]
            
          
          
=> ALTER SYSTEM SET wal_compression = on;
=> SELECT pg_reload_conf();
=> CHECKPOINT;

  
=> SELECT pg_current_wal_insert_lsn();
pg_current_wal_insert_lsn
−−−−−−−−−−−−−−−−−−−−−−−−−−−
0/44D4C228
(1 row)
postgres$ /usr/local/pgsql/bin/pgbench -t 20000 internals
=> SELECT pg_current_wal_insert_lsn();
pg_current_wal_insert_lsn
−−−−−−−−−−−−−−−−−−−−−−−−−−−
0/457653B0
(1 row)
       
=> SELECT pg_size_pretty('0/457653B0'::pg_lsn - '0/44D4C228'::pg_lsn);
pg_size_pretty
−−−−−−−−−−−−−−−−
10 MB
(1 row)
postgres$ /usr/local/pgsql/bin/pg_waldump --stats \
-p /usr/local/pgsql/data/pg_wal -s 0/44D4C228 -e 0/457653B0
Type N (%) Record size (%) FPI size (%)
−−−− −−− −−−−−−−−−−− −−− −−−−−−−− −−−
XLOG 344 ( 0,29) 17530 ( 0,22) 435492 ( 17,75)
Transaction 20001 ( 16,73) 680114 ( 8,68) 0 ( 0,00)
Storage 1 ( 0,00) 42 ( 0,00) 0 ( 0,00)
Standby 5 ( 0,00) 330 ( 0,00) 0 ( 0,00)
Heap2 18946 ( 15,84) 1207425 ( 15,42) 101601 ( 4,14)
Heap 80141 ( 67,02) 5918020 ( 75,56) 1627008 ( 66,31)
Btree 143 ( 0,12) 8443 ( 0,11) 289654 ( 11,80)
−−−−−− −−−−−−−− −−−−−−−−
Total 119581 7831904 [76,14%] 2453755 [23,86%]
              
           
   
 
             
             

   
         
            
       replica     
 

          
           
               
           
            
      
             
            
            
     
               
      2MB  
        
             
             
    10  
=> ALTER SYSTEM SET wal_level = minimal;
=> ALTER SYSTEM SET max_wal_senders = 0;
           
postgres$ pg_ctl restart -l /home/postgres/logfile
    
=> SELECT pg_current_wal_insert_lsn();
  

  
pg_current_wal_insert_lsn
−−−−−−−−−−−−−−−−−−−−−−−−−−−
0/45767698
(1 row)
            
   
=> BEGIN;
=> TRUNCATE TABLE wal;
=> INSERT INTO wal
SELECT id FROM generate_series(1,100000) id;
=> COMMIT;
=> SELECT pg_current_wal_insert_lsn();
pg_current_wal_insert_lsn
−−−−−−−−−−−−−−−−−−−−−−−−−−−
0/45767840
(1 row)
             

          
postgres$ /usr/local/pgsql/bin/pg_waldump \
-p /usr/local/pgsql/data/pg_wal -s 0/45767698 -e 0/45767840
#
rmgr: Storage len (rec/tot): 42/ 42, tx: 0, lsn:
0/45767698, prev 0/45767660, desc: CREATE base/16391/24784
rmgr: Heap len (rec/tot): 123/ 123, tx: 122844, lsn:
0/457676C8, prev 0/45767698, desc: UPDATE off 45 xmax 122844 flags
0x60 ; new off 48 xmax 0, blkref #0: rel 1663/16391/1259 blk 0
rmgr: Btree len (rec/tot): 64/ 64, tx: 122844, lsn:
0/45767748, prev 0/457676C8, desc: INSERT_LEAF off 176, blkref #0:
rel 1663/16391/2662 blk 2
rmgr: Btree len (rec/tot): 64/ 64, tx: 122844, lsn:
0/45767788, prev 0/45767748, desc: INSERT_LEAF off 147, blkref #0:
rel 1663/16391/2663 blk 2
rmgr: Btree len (rec/tot): 64/ 64, tx: 122844, lsn:
0/457677C8, prev 0/45767788, desc: INSERT_LEAF off 254, blkref #0:
rel 1663/16391/3455 blk 4
rmgr: Transaction len (rec/tot): 54/ 54, tx: 122844, lsn:
0/45767808, prev 0/457677C8, desc: COMMIT 2023−03−06 14:03:58.395214
MSK; rels: base/16391/24783

   
              
  
           
         
         

              
            
            
              
          
                
          
             
      
            
               
              
           
            
      
                
             
            
    
  


  
              
     
=> ALTER SYSTEM RESET wal_level;
=> ALTER SYSTEM RESET max_wal_senders;
postgres$ pg_ctl restart -l /home/postgres/logfile
               
  
=> SELECT pg_current_wal_insert_lsn();
pg_current_wal_insert_lsn
−−−−−−−−−−−−−−−−−−−−−−−−−−−
0/45D88E48
(1 row)
=> BEGIN;
=> TRUNCATE TABLE wal;
=> INSERT INTO wal VALUES (42);
=> COMMIT;
=> SELECT pg_current_wal_insert_lsn();
pg_current_wal_insert_lsn
−−−−−−−−−−−−−−−−−−−−−−−−−−−
0/45D89108
(1 row)
     
               

       
   
           
     

   
postgres$ /usr/local/pgsql/bin/pg_waldump \
-p /usr/local/pgsql/data/pg_wal -s 0/45D88E48 -e 0/45D89108
rmgr: Standby len (rec/tot): 42/ 42, tx: 122846, lsn:
0/45D88E48, prev 0/45D88DD0, desc: LOCK xid 122846 db 16391 rel 16562
rmgr: Storage len (rec/tot): 42/ 42, tx: 122846, lsn:
0/45D88E78, prev 0/45D88E48, desc: CREATE base/16391/24786
rmgr: Heap len (rec/tot): 123/ 123, tx: 122846, lsn:
0/45D88EA8, prev 0/45D88E78, desc: UPDATE off 49 xmax 122846 flags
0x60 ; new off 50 xmax 0, blkref #0: rel 1663/16391/1259 blk 0
rmgr: Btree len (rec/tot): 64/ 64, tx: 122846, lsn:
0/45D88F28, prev 0/45D88EA8, desc: INSERT_LEAF off 178, blkref #0:
rel 1663/16391/2662 blk 2
rmgr: Btree len (rec/tot): 64/ 64, tx: 122846, lsn:
0/45D88F68, prev 0/45D88F28, desc: INSERT_LEAF off 149, blkref #0:
rel 1663/16391/2663 blk 2
rmgr: Btree len (rec/tot): 64/ 64, tx: 122846, lsn:
0/45D88FA8, prev 0/45D88F68, desc: INSERT_LEAF off 256, blkref #0:
rel 1663/16391/3455 blk 4
rmgr: Heap len (rec/tot): 59/ 59, tx: 122846, lsn:
0/45D88FE8, prev 0/45D88FA8, desc: INSERT+INIT off 1 flags 0x00,
blkref #0: rel 1663/16391/24786 blk 0
rmgr: Standby len (rec/tot): 42/ 42, tx: 0, lsn:
0/45D89028, prev 0/45D88FE8, desc: LOCK xid 122846 db 16391 rel 16562
rmgr: Standby len (rec/tot): 54/ 54, tx: 0, lsn:
0/45D89058, prev 0/45D89028, desc: RUNNING_XACTS nextXid 122847
latestCompletedXid 122845 oldestRunningXid 122846; 1 xacts: 122846
rmgr: Transaction len (rec/tot): 114/ 114, tx: 122846, lsn:
0/45D89090, prev 0/45D89058, desc: COMMIT 2023−03−06 14:04:14.538399
MSK; rels: base/16391/24785; inval msgs: catcache 51 catcache 50
relcache 16562

            
        
                 
            
            
         
       

Part III
Locks
12
Relation-Level Locks
  
      
             
             
           
               
            
            
             
            
           
        
             
            
       
             
           
          
              
        
                
      

   
              
         
             
           
           
              
             
               
      
            
            

            
            
            
   
           
           
           
          
      
        
           
           
             
        
            
      
          
   

  
       
             
           
          
     
         
         
         
         
            
          
        
          
      
         
            
             
               
  
            
              
           
           
               
       
         



   
           
          64 
  100 
            
          
               
            
 
             
             
             
             
           
             
           
          
          
          
         
              
    
       
   
     
         
    
        
    


    
           
        
          
       
    
               
 
           
           
         
Shared Exclusive
Shared
Exclusive
         
            
              
            
              
           
          
             

=> BEGIN;
=> SELECT pg_backend_pid();
pg_backend_pid
−−−−−−−−−−−−−−−−
28980
(1 row)
           

   
=> SELECT locktype, virtualxid, mode, granted
FROM pg_locks WHERE pid = 28980;
locktype | virtualxid | mode | granted
−−−−−−−−−−−−+−−−−−−−−−−−−+−−−−−−−−−−−−−−−+−−−−−−−−−
virtualxid | 5/2 | ExclusiveLock | t
(1 row)
              
            
           
             
=> SELECT pg_current_xact_id();
pg_current_xact_id
−−−−−−−−−−−−−−−−−−−−
122849
(1 row)
=> SELECT locktype, virtualxid, transactionid AS xid, mode, granted
FROM pg_locks WHERE pid = 28980;
locktype | virtualxid | xid | mode | granted
−−−−−−−−−−−−−−−+−−−−−−−−−−−−+−−−−−−−−+−−−−−−−−−−−−−−−+−−−−−−−−−
virtualxid | 5/2 | | ExclusiveLock | t
transactionid | | 122849 | ExclusiveLock | t
(2 rows)
         
  
             
            
         
           
            
               


  
           
     
AS RS RE SUE S SRE E AE
Access Share SELECT
Row Share SELECT FOR UPDATE/SHARE
Row Exclusive INSERT, UPDATE, DELETE
Share Update Exclusive VACUUM, CREATE INDEX CONCURRENTLY
Share  CREATE INDEX
Share Row Exclusive CREATE TRIGGER
Exclusive REFRESH MAT. VIEW CONCURRENTLY
Access Exclusive DROP, TRUNCATE, VACUUM FULL,
LOCK TABLE, REFRESH MAT. VIEW
               
           
               
     
            
             
            
           
           
 
          
          
             
          
           
         
   


   
            
=> TRUNCATE accounts;
=> INSERT INTO accounts(id, client, amount)
VALUES
(1, 'alice', 100.00),
(2, 'bob', 200.00),
(3, 'charlie', 300.00);
              
           
=> CREATE VIEW locks AS
SELECT pid,
locktype,
CASE locktype
WHEN 'relation' THEN relation::regclass::text
WHEN 'transactionid' THEN transactionid::text
WHEN 'virtualxid' THEN virtualxid
END AS lockid,
mode,
granted
FROM pg_locks
ORDER BY 1, 2, 3;
             
               
        
=> UPDATE accounts SET amount = amount + 100.00 WHERE id = 1;
=> SELECT locktype, lockid, mode, granted
FROM locks WHERE pid = 28980;
locktype | lockid | mode | granted
−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−−−+−−−−−−−−−
relation | accounts | RowExclusiveLock | t
relation | accounts_pkey | RowExclusiveLock | t
transactionid | 122849 | ExclusiveLock | t
virtualxid | 5/2 | ExclusiveLock | t
(4 rows)

  
  
            
              
       
                
   
=> SELECT pg_backend_pid();
pg_backend_pid
−−−−−−−−−−−−−−−−
29459
(1 row)
=> CREATE INDEX ON accounts(client);
            
           
=> SELECT locktype, lockid, mode, granted
FROM locks WHERE pid = 29459;
locktype | lockid | mode | granted
−−−−−−−−−−−−+−−−−−−−−−−+−−−−−−−−−−−−−−−+−−−−−−−−−
relation | accounts | ShareLock | f
virtualxid | 6/3 | ExclusiveLock | t
(2 rows)
               
            

=> SELECT pg_backend_pid();
pg_backend_pid
−−−−−−−−−−−−−−−−
29662
(1 row)
=> VACUUM FULL accounts;
  

   
=> SELECT locktype, lockid, mode, granted
FROM locks WHERE pid = 29662;
locktype | lockid | mode | granted
−−−−−−−−−−−−−−−+−−−−−−−−−−+−−−−−−−−−−−−−−−−−−−−−+−−−−−−−−−
relation | accounts | AccessExclusiveLock | f
transactionid | 122853 | ExclusiveLock | t
virtualxid | 7/4 | ExclusiveLock | t
(3 rows)
             
           
             
  
=> SELECT pg_backend_pid();
pg_backend_pid
−−−−−−−−−−−−−−−−
29872
(1 row)
=> SELECT *FROM accounts;
=> SELECT locktype, lockid, mode, granted
FROM locks WHERE pid = 29872;
locktype | lockid | mode | granted
−−−−−−−−−−−−+−−−−−−−−−−+−−−−−−−−−−−−−−−−−+−−−−−−−−−
relation | accounts | AccessShareLock | f
virtualxid | 8/3 | ExclusiveLock | t
(2 rows)
T1
UPDATE
relation
T2
CREATE INDEX
T3
VACUUM FULL
T4
SELECT

  
          
              
      
=> SELECT pid,
pg_blocking_pids(pid),
wait_event_type,
state,
left(query,50) AS query
FROM pg_stat_activity
WHERE pid IN (28980,29459,29662,29872) \gx
−[ RECORD 1 ]−−−−+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
pid | 28980
pg_blocking_pids | {}
wait_event_type | Client
state | idle in transaction
query | UPDATE accounts SET amount = amount + 100.00 WHERE
−[ RECORD 2 ]−−−−+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
pid | 29459
pg_blocking_pids | {28980}
wait_event_type | Lock
state | active
query | CREATE INDEX ON accounts(client);
−[ RECORD 3 ]−−−−+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
pid | 29662
pg_blocking_pids | {28980,29459}
wait_event_type | Lock
state | active
query | VACUUM FULL accounts;
−[ RECORD 4 ]−−−−+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
pid | 29872
pg_blocking_pids | {29662}
wait_event_type | Lock
state | active
query | SELECT * FROM accounts;
            
            
            

   

   
            
   
=> ROLLBACK;
ROLLBACK
CREATE INDEX
VACUUM
id | client | amount
−−−−+−−−−−−−−−+−−−−−−−−
1 | alice | 100.00
2 | bob | 200.00
3 | charlie | 300.00
(3 rows)

13
Row-Level Locks
  
             
             
               
              
           
           
    
           
            
          
  
            
             
               
               
              
               
             
             
               
            
            

   
             
          
              
           
          
          
   
          
            
         
       
Key Share Share No Key
Update Update
Key Share
Share
No Key Update 
Update 
 
            
             
             
 
         
            



   
           
           
=> CREATE FUNCTION row_locks(relname text, pageno integer)
RETURNS TABLE(
ctid tid, xmax text,
lock_only text, is_multi text,
keys_upd text, keyshr text,
shr text
)
AS $$
SELECT (pageno,lp)::text::tid,
t_xmax,
CASE WHEN t_infomask & 128 = 128 THEN 't' END,
CASE WHEN t_infomask & 4096 = 4096 THEN 't' END,
CASE WHEN t_infomask2 & 8192 = 8192 THEN 't' END,
CASE WHEN t_infomask & 16 = 16 THEN 't' END,
CASE WHEN t_infomask & 16+64 = 16+64 THEN 't' END
FROM heap_page_items(get_raw_page(relname,pageno))
ORDER BY lp;
$$ LANGUAGE sql;
             
               

=> BEGIN;
=> UPDATE accounts SET amount = amount + 100.00 WHERE id = 1;
=> UPDATE accounts SET id = 20 WHERE id = 2;
      
=> SELECT *FROM row_locks('accounts',0) LIMIT 2;
ctid | xmax | lock_only | is_multi | keys_upd | keyshr | shr
−−−−−−−+−−−−−−−−+−−−−−−−−−−−+−−−−−−−−−−+−−−−−−−−−−+−−−−−−−−+−−−−−
(0,1) | 122858 | | | | |
(0,2) | 122858 | | | t | |
(2 rows)
         
=> ROLLBACK;

   
             
              
            
=> BEGIN;
=> SELECT *FROM accounts WHERE id = 1 FOR NO KEY UPDATE;
=> SELECT *FROM accounts WHERE id = 2 FOR UPDATE;
=> SELECT *FROM row_locks('accounts',0) LIMIT 2;
ctid | xmax | lock_only | is_multi | keys_upd | keyshr | shr
−−−−−−−+−−−−−−−−+−−−−−−−−−−−+−−−−−−−−−−+−−−−−−−−−−+−−−−−−−−+−−−−−
(0,1) | 122859 | t | | | |
(0,2) | 122859 | t | | t | |
(2 rows)
=> ROLLBACK;
 
              
          
     
              
              
           
            
            
=> BEGIN;
=> SELECT *FROM accounts WHERE id = 1 FOR KEY SHARE;
=> SELECT *FROM accounts WHERE id = 2 FOR SHARE;
        
=> SELECT *FROM row_locks('accounts',0) LIMIT 2;
ctid | xmax | lock_only | is_multi | keys_upd | keyshr | shr
−−−−−−−+−−−−−−−−+−−−−−−−−−−−+−−−−−−−−−−+−−−−−−−−−−+−−−−−−−−+−−−−−
(0,1) | 122860 | t | | | t |
(0,2) | 122860 | t | | | t | t
(2 rows)

 
             
    
 
               
                
       
        
         
            
           
             

             
         
           
   
           
     
=> BEGIN;
=> UPDATE accounts SET amount = amount + 100.00 WHERE id = 1;
=> SELECT *FROM row_locks('accounts',0) LIMIT 2;
ctid | xmax | lock_only | is_multi | keys_upd | keyshr | shr
−−−−−−−+−−−−−−−−+−−−−−−−−−−−+−−−−−−−−−−+−−−−−−−−−−+−−−−−−−−+−−−−−
(0,1) | 1 | | t | | |
(0,2) | 122860 | t | | | t | t
(2 rows)




   
           
  
         
         
=> CREATE EXTENSION pgrowlocks;
=> SELECT *FROM pgrowlocks('accounts') \gx
−[ RECORD 1 ]−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
locked_row | (0,1)
locker | 1
multi | t
xids | {122860,122861}
modes | {"Key Share","No Key Update"}
pids | {30423,30723}
−[ RECORD 2 ]−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
locked_row | (0,2)
locker | 122860
multi | f
xids | {122860}
modes | {"For Share"}
pids | {30423}
             
          
=> COMMIT;
=> ROLLBACK;
             
           
              
              

             
               
             
      
  

  
         
       
  
  
  
 
            
             
                
            

           
             
 
               
           
              
      
               
           
               
            
             
            
             
       


   
            
              
               
            
             
      
=> CREATE VIEW locks_accounts AS
SELECT pid,
locktype,
CASE locktype
WHEN 'relation' THEN relation::regclass::text
WHEN 'transactionid' THEN transactionid::text
WHEN 'tuple' THEN relation::regclass||'('||page||','||tuple||')'
END AS lockid,
mode,
granted
FROM pg_locks
WHERE locktype in ('relation','transactionid','tuple')
AND (locktype != 'relation' OR relation = 'accounts'::regclass)
ORDER BY 1, 2, 3;
       
=> BEGIN;
=> SELECT txid_current(), pg_backend_pid();
txid_current | pg_backend_pid
−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−
122863 | 30723
(1 row)
=> UPDATE accounts SET amount = amount + 100.00 WHERE id = 1;
              
   
=> SELECT *FROM locks_accounts WHERE pid = 30723;
pid | locktype | lockid | mode | granted
−−−−−−−+−−−−−−−−−−−−−−−+−−−−−−−−−−+−−−−−−−−−−−−−−−−−−+−−−−−−−−−
30723 | relation | accounts | RowExclusiveLock | t
30723 | transactionid | 122863 | ExclusiveLock | t
(2 rows)
             
   

  
=> BEGIN;
=> SELECT txid_current(), pg_backend_pid();
txid_current | pg_backend_pid
−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−
122864 | 30794
(1 row)
=> UPDATE accounts SET amount = amount + 100.00 WHERE id = 1;
T1
No Key Update
T2
tuple (0,1)
ctid xmin xmax data
(0,1) T1
              
                
                
          
=> SELECT *FROM locks_accounts WHERE pid = 30794;
pid | locktype | lockid | mode | granted
−−−−−−−+−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−−−+−−−−−−−−−
30794 | relation | accounts | RowExclusiveLock | t
30794 | transactionid | 122863 | ShareLock | f
30794 | transactionid | 122864 | ExclusiveLock | t
30794 | tuple | accounts(0,1) | ExclusiveLock | t
(4 rows)
                
       
=> BEGIN;
=> SELECT txid_current(), pg_backend_pid();
txid_current | pg_backend_pid
−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−
122865 | 30865
(1 row)
=> UPDATE accounts SET amount = amount + 100.00 WHERE id = 1;

   
=> SELECT *FROM locks_accounts WHERE pid = 30865;
pid | locktype | lockid | mode | granted
−−−−−−−+−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−−−+−−−−−−−−−
30865 | relation | accounts | RowExclusiveLock | t
30865 | transactionid | 122865 | ExclusiveLock | t
30865 | tuple | accounts(0,1) | ExclusiveLock | f
(3 rows)
             
               
  
=> BEGIN;
=> SELECT txid_current(), pg_backend_pid();
txid_current | pg_backend_pid
−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−
122866 | 30936
(1 row)
=> UPDATE accounts SET amount = amount + 100.00 WHERE id = 1;
=> SELECT *FROM locks_accounts WHERE pid = 30865;
pid | locktype | lockid | mode | granted
−−−−−−−+−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−−−+−−−−−−−−−
30865 | relation | accounts | RowExclusiveLock | t
30865 | transactionid | 122865 | ExclusiveLock | t
30865 | tuple | accounts(0,1) | ExclusiveLock | f
(3 rows)
T1
No Key Update
T2
tuple (0,1)
T3
T4
ctid xmin xmax data
(0,1) T1
             
     

  
=> SELECT pid,
wait_event_type,
wait_event,
pg_blocking_pids(pid)
FROM pg_stat_activity
WHERE pid IN (30723,30794,30865,30936);
pid | wait_event_type | wait_event | pg_blocking_pids
−−−−−−−+−−−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−−−
30723 | Client | ClientRead | {}
30794 | Lock | transactionid | {30723}
30865 | Lock | tuple | {30794}
30936 | Lock | tuple | {30794,30865}
(4 rows)
             
          
              
           
            
             
            
     
=> COMMIT;
           
    
UPDATE 1
=> SELECT *FROM locks_accounts WHERE pid = 30794;
pid | locktype | lockid | mode | granted
−−−−−−−+−−−−−−−−−−−−−−−+−−−−−−−−−−+−−−−−−−−−−−−−−−−−−+−−−−−−−−−
30794 | relation | accounts | RowExclusiveLock | t
30794 | transactionid | 122864 | ExclusiveLock | t
(2 rows)
              
               
  

   
           
              
             
    
=> SELECT *FROM locks_accounts WHERE pid = 30865;
pid | locktype | lockid | mode | granted
−−−−−−−+−−−−−−−−−−−−−−−+−−−−−−−−−−+−−−−−−−−−−−−−−−−−−+−−−−−−−−−
30865 | relation | accounts | RowExclusiveLock | t
30865 | transactionid | 122864 | ShareLock | f
30865 | transactionid | 122865 | ExclusiveLock | t
(3 rows)
     
=> SELECT *FROM locks_accounts WHERE pid = 30936;
pid | locktype | lockid | mode | granted
−−−−−−−+−−−−−−−−−−−−−−−+−−−−−−−−−−+−−−−−−−−−−−−−−−−−−+−−−−−−−−−
30936 | relation | accounts | RowExclusiveLock | t
30936 | transactionid | 122864 | ShareLock | f
30936 | transactionid | 122866 | ExclusiveLock | t
(3 rows)
              
            
T2
No Key Update
T3 T4
ctid xmin xmax data
(0,1) T1
(0,2) T1 T2
              
     
  

  
               
           
    
     
=> COMMIT;
UPDATE 1
=> COMMIT;
UPDATE 1
=> COMMIT;
 
          
          
     
         
               
      
            
             
 
               
           
             
   
       
=> TRUNCATE accounts;

   
=> INSERT INTO accounts(id, client, amount)
VALUES
(1,'alice',100.00),
(2,'bob',200.00),
(3,'charlie',300.00);
   
=> BEGIN;
=> SELECT txid_current(), pg_backend_pid();
txid_current | pg_backend_pid
−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−
122869 | 30723
(1 row)
       
=> SELECT *FROM accounts WHERE id = 1 FOR SHARE;
              
      
=> BEGIN;
=> SELECT txid_current(), pg_backend_pid();
txid_current | pg_backend_pid
−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−
122870 | 30794
(1 row)
=> UPDATE accounts SET amount = amount + 100.00 WHERE id = 1;
            
       
=> SELECT *FROM locks_accounts WHERE pid = 30794;
pid | locktype | lockid | mode | granted
−−−−−−−+−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−−−+−−−−−−−−−
30794 | relation | accounts | RowExclusiveLock | t
30794 | transactionid | 122869 | ShareLock | f
30794 | transactionid | 122870 | ExclusiveLock | t
30794 | tuple | accounts(0,1) | ExclusiveLock | t
(4 rows)

  
T1
Share
T2
tuple (0,1)
ctid xmin xmax data
(0,1) T1
              
           
=> BEGIN;
=> SELECT txid_current(), pg_backend_pid();
txid_current | pg_backend_pid
−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−
122871 | 30865
(1 row)
=> SELECT *FROM accounts WHERE id = 1 FOR SHARE;
       
=> SELECT *FROM pgrowlocks('accounts') \gx
−[ RECORD 1 ]−−−−−−−−−−−−−−−
locked_row | (0,1)
locker | 2
multi | t
xids | {122869,122871}
modes | {Share,Share}
pids | {30723,30865}
T1 T3
Share
T2
tuple (0,1)
ctid xmin xmax data
(0,1) multi

   
               
                 
    
=> COMMIT;
=> SELECT *FROM locks_accounts WHERE pid = 30794;
pid | locktype | lockid | mode | granted
−−−−−−−+−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−−−+−−−−−−−−−
30794 | relation | accounts | RowExclusiveLock | t
30794 | transactionid | 122870 | ExclusiveLock | t
30794 | transactionid | 122871 | ShareLock | f
30794 | tuple | accounts(0,1) | ExclusiveLock | t
(4 rows)
              
           
=> COMMIT;
UPDATE 1
=> COMMIT;
             
             
        
  
            
             
           
  
=> BEGIN;
=> UPDATE accounts SET amount = amount + 100.00 WHERE id = 1;

  
            
   
=> SELECT *FROM accounts
FOR UPDATE NOWAIT;
ERROR: could not obtain lock on row in relation "accounts"
          
             
              
       
               
             
     
=> SELECT *FROM accounts
ORDER BY id
FOR UPDATE SKIP LOCKED
LIMIT 1;
id | client | amount
−−−−+−−−−−−−−+−−−−−−−−
2 | bob | 200.00
(1 row)
             
    
               
          
       
          
=> SET lock_timeout = '1s';
=> ALTER TABLE accounts DROP COLUMN amount;
ERROR: canceling statement due to lock timeout
             
               
     

   
           
             
    
           
           
=> ROLLBACK;
 
         
           
           

           
                
         
  
           
             
              
          
           
            
              
            
            
            
  
            
              



 
T1
resource 1
T2
resource 2
T3
resource 3
            
        1s
         
             
           
            
           
         
              
 
             
           
             
            
         
         
              
       
  
  


   
  
           
         
            
      
=> BEGIN;
=> UPDATE accounts SET amount = amount - 100.00 WHERE id = 1;
UPDATE 1
            
              
=> BEGIN;
=> UPDATE accounts SET amount = amount - 10.00 WHERE id = 2;
UPDATE 1
            
       
=> UPDATE accounts SET amount = amount + 100.00 WHERE id = 2;
             
=> UPDATE accounts SET amount = amount + 10.00 WHERE id = 1;
             
           
  
ERROR: deadlock detected
DETAIL: Process 30423 waits for ShareLock on transaction 122877;
blocked by process 30723.
Process 30723 waits for ShareLock on transaction 122876; blocked by
process 30423.
HINT: See server log for query details.
CONTEXT: while updating tuple (0,2) in relation "accounts"
            

 
UPDATE 1
   
=> ROLLBACK;
=> ROLLBACK;
               
            
    
    
          
            
             
              
              
   
             
   
=> CREATE INDEX ON accounts(amount DESC);
             
=> CREATE FUNCTION inc_slow(n numeric)
RETURNS numeric
AS $$
SELECT pg_sleep(1);
SELECT n + 100.00;
$$ LANGUAGE sql;
             
       

   
=> EXPLAIN (costs off)
UPDATE accounts SET amount = inc_slow(amount);
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−
Update on accounts
−> Seq Scan on accounts
(2 rows)
              
            
=> TRUNCATE accounts;
=> INSERT INTO accounts(id, client, amount)
VALUES
(1,'alice',100.00),
(2,'bob',200.00),
(3,'charlie',300.00);
=> ANALYZE accounts;
=> SELECT ctid, * FROM accounts;
ctid | id | client | amount
−−−−−−−+−−−−+−−−−−−−−−+−−−−−−−−
(0,1) | 1 | alice | 100.00
(0,2) | 2 | bob | 200.00
(0,3) | 3 | charlie | 300.00
(3 rows)
               
    
   
=> UPDATE accounts SET amount = inc_slow(amount);
          
=> SET enable_seqscan = off;
            
=> EXPLAIN (costs off)
UPDATE accounts SET amount = inc_slow(amount)
WHERE amount > 100.00;

 
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Update on accounts
−> Index Scan using accounts_amount_idx on accounts
Index Cond: (amount > 100.00)
(3 rows)
             
       
    
=> UPDATE accounts SET amount = inc_slow(amount)
WHERE amount > 100.00;
           
              
=> SELECT locked_row, locker, modes FROM pgrowlocks('accounts');
locked_row | locker | modes
−−−−−−−−−−−−+−−−−−−−−+−−−−−−−−−−−−−−−−−−−
(0,1) | 122883 | {"No Key Update"}
(0,3) | 122884 | {"No Key Update"}
(2 rows)
rst
second
            
            
=> SELECT locked_row, locker, modes FROM pgrowlocks('accounts');
locked_row | locker | modes
−−−−−−−−−−−−+−−−−−−−−+−−−−−−−−−−−−−−−−−−−
(0,1) | 122883 | {"No Key Update"}
(0,2) | 122883 | {"No Key Update"}
(0,3) | 122884 | {"No Key Update"}
(3 rows)
the rst one wins
               
      
     

   
ERROR: deadlock detected
DETAIL: Process 30794 waits for ShareLock on transaction 122883;
blocked by process 30723.
Process 30723 waits for ShareLock on transaction 122884; blocked by
process 30794.
HINT: See server log for query details.
CONTEXT: while updating tuple (0,2) in relation "accounts"
     
UPDATE 3
          
     

14
Miscellaneous Locks
  
         
              
        
   
     
=> BEGIN;
=> CREATE TABLE example(n integer);
         
=> SELECT database,
(
SELECT datname FROM pg_database WHERE oid = database
)AS dbname,
classid,
(
SELECT relname FROM pg_class WHERE oid = classid
)AS classname,
objid,
mode,
granted
FROM pg_locks
WHERE locktype = 'object'
AND pid = pg_backend_pid() \gx
   

   
−[ RECORD 1 ]−−−−−−−−−−−−−−
database | 16391
dbname | internals
classid | 2615
classname | pg_namespace
objid | 2200
mode | AccessShareLock
granted | t
        
             
        
             
       
           
              
           
  
     
=> SELECT nspname FROM pg_namespace WHERE oid = 2200;
nspname
−−−−−−−−−
public
(1 row)
              
      
            
    
=> ROLLBACK;
  

   
   
             
              
                 
             
        
               
             
         
            
             
  
            
           
              
            
         
              
              
                
  
            
    
  
  
  
  

   
              
            
            
            
         
 on           
            
           
       
           
              
            
           
              

  
          
        
            
  
             
              
             
            
=> SELECT hashtext('resource1');
hashtext
−−−−−−−−−−−
991601810
(1 row)


  
         
            
    
  
         
   
           
              
       
          
=> BEGIN;
=> SELECT pg_advisory_lock(hashtext('resource1'));
=> SELECT locktype, objid, mode, granted
FROM pg_locks WHERE locktype = 'advisory' AND pid = pg_backend_pid();
locktype | objid | mode | granted
−−−−−−−−−−+−−−−−−−−−−−+−−−−−−−−−−−−−−−+−−−−−−−−−
advisory | 991601810 | ExclusiveLock | t
(1 row)
            
            
           
=> COMMIT;
=> SELECT locktype, objid, mode, granted
FROM pg_locks WHERE locktype = 'advisory' AND pid = pg_backend_pid();
locktype | objid | mode | granted
−−−−−−−−−−+−−−−−−−−−−−+−−−−−−−−−−−−−−−+−−−−−−−−−
advisory | 991601810 | ExclusiveLock | t
(1 row)
              
=> SELECT pg_advisory_unlock(hashtext('resource1'));


   
  
             
           
              
              
  
            
             
              
           
             
            
       
          
          
              
          
              
            
             
    
           
            
 
            
 
                  
 



  
          
             
             
             
              
       
              
         
            
  
              
    
=> CREATE TABLE pred(n numeric, s text);
=> INSERT INTO pred(n) SELECT nFROM generate_series(1,10000) n;
=> CREATE INDEX ON pred(n) WITH (fillfactor = 10);
=> ANALYZE pred;
            
             
=> SELECT pg_backend_pid();
pg_backend_pid
−−−−−−−−−−−−−−−−
34753
(1 row)
=> BEGIN ISOLATION LEVEL SERIALIZABLE;
=> EXPLAIN (analyze, costs off, timing off, summary off)
SELECT *FROM pred WHERE n > 100;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Seq Scan on pred (actual rows=9900 loops=1)
Filter: (n > '100'::numeric)
Rows Removed by Filter: 100
(3 rows)

   
          
           
        
=> SELECT relation::regclass, locktype, page, tuple
FROM pg_locks WHERE mode = 'SIReadLock' AND pid = 34753
ORDER BY 1, 2, 3, 4;
relation | locktype | page | tuple
−−−−−−−−−−+−−−−−−−−−−+−−−−−−+−−−−−−−
pred | relation | |
(1 row)
=> ROLLBACK;
            
           
 
             
               
                
 
=> BEGIN ISOLATION LEVEL SERIALIZABLE;
=> EXPLAIN (analyze, costs off, timing off, summary off)
SELECT *FROM pred WHERE nBETWEEN 1000 AND 1001;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Index Scan using pred_n_idx on pred (actual rows=2 loops=1)
Index Cond: ((n >= '1000'::numeric) AND (n <= '1001'::numeric))
(2 rows)
=> SELECT relation::regclass, locktype, page, tuple
FROM pg_locks WHERE mode = 'SIReadLock' AND pid = 34753
ORDER BY 1, 2, 3, 4;
relation | locktype | page | tuple
−−−−−−−−−−−−+−−−−−−−−−−+−−−−−−+−−−−−−−
pred | tuple | 4 | 96
pred | tuple | 4 | 97
pred_n_idx | page | 28 |
(3 rows)

  
            
               
           
=> INSERT INTO pred
SELECT 1000+(n/1000.0) FROM generate_series(1,999) n;
=> SELECT relation::regclass, locktype, page, tuple
FROM pg_locks WHERE mode = 'SIReadLock' AND pid = 34753
ORDER BY 1, 2, 3, 4;
relation | locktype | page | tuple
−−−−−−−−−−−−+−−−−−−−−−−+−−−−−−+−−−−−−−
pred | tuple | 4 | 96
pred | tuple | 4 | 97
pred_n_idx | page | 28 |
pred_n_idx | page | 266 |
pred_n_idx | page | 267 |
pred_n_idx | page | 268 |
pred_n_idx | page | 269 |
(7 rows)
              
             
       64  
 100         
   
               
    
                
2       
=> EXPLAIN (analyze, costs off, timing off, summary off)
SELECT *FROM pred WHERE nBETWEEN 1000 AND 1002;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Index Scan using pred_n_idx on pred (actual rows=3 loops=1)
Index Cond: ((n >= '1000'::numeric) AND (n <= '1002'::numeric))
(2 rows)
  

   
                
=> SELECT relation::regclass, locktype, page, tuple
FROM pg_locks WHERE mode = 'SIReadLock' AND pid = 34753
ORDER BY 1, 2, 3, 4;
relation | locktype | page | tuple
−−−−−−−−−−−−+−−−−−−−−−−+−−−−−−+−−−−−−−
pred | page | 4 |
pred_n_idx | page | 28 |
pred_n_idx | page | 266 |
pred_n_idx | page | 267 |
pred_n_idx | page | 268 |
pred_n_idx | page | 269 |
(6 rows)
=> ROLLBACK;
             
     −2   
           
     64    
         
           
           
        
      

     
              
               
          
            
             
          
  

  
            
            
    

15
Locks on Memory Structures
 
          
         
            
            
 
         
            
            
             
       
             
             

         
          
       


  
  
          
            
            
  
          
             
                
           
  
           
          
       
 
             
            
                
    
 
             
          
          


     
hash table
BufferMapping ×128
free buffers
clock hand
buffer strategy
BufferIO
BufferContent
buffer header
buffer
pin
            
          
        
               
               
            
           
           
             
    
           
              
             
             

  
  


 
            
              
            
         
              
      
 
WALWrite
PrevBytePos
CurBytePos
insert position WALInsert ×8
WALBufMapping
hash table
              
          
      
        
  
           
         
            
             
         
  

  
  

     
              
           
  
  
          
              

             off 
            
    1s       
      
           
      
              
            
 
      
       
  
  
  
        
           
  


  
              
     
      
            
            
  
      
 
              
           
            
              
                 
            
             
  
=> SELECT backend_type, wait_event_type AS event_type, wait_event
FROM pg_stat_activity;
backend_type | event_type | wait_event
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+−−−−−−−−−−−−+−−−−−−−−−−−−−−−−−−−−−
logical replication launcher | Activity | LogicalLauncherMain
autovacuum launcher | Activity | AutoVacuumMain
client backend | |
background writer | Activity | BgWriterMain
checkpointer | Activity | CheckpointerMain
walwriter | Activity | WalWriterMain
(6 rows)
             
            



     
 
         
             
       
            
              
            
             
         
             
           
      
=> ALTER SYSTEM SET shared_preload_libraries = 'pg_wait_sampling';
postgres$ pg_ctl restart -l /home/postgres/logfile
       
=> CREATE EXTENSION pg_wait_sampling;
              
           
       
            
           
postgres$ /usr/local/pgsql/bin/pgbench -T 60 internals
=> SELECT pid FROM pg_stat_activity
WHERE application_name = 'pgbench';
pid
−−−−−−−
36367
(1 row)
           


 
=> SELECT pid, event_type, event, count
FROM pg_wait_sampling_profile WHERE pid = 36367
ORDER BY count DESC LIMIT 4;
pid | event_type | event | count
−−−−−−−+−−−−−−−−−−−−+−−−−−−−−−−−−−−+−−−−−−−
36367 | IO | WALSync | 3478
36367 | IO | WALWrite | 52
36367 | Client | ClientRead | 30
36367 | IO | DataFileRead | 2
(4 rows)
     10ms    
               
    
               
            
           
           
               
            
postgres$ /usr/local/pgsql/bin/pgbench -T 60 internals
=> SELECT pid FROM pg_stat_activity
WHERE application_name = 'pgbench';
pid
−−−−−−−
36747
(1 row)
=> SELECT pid, event_type, event, count
FROM pg_wait_sampling_profile WHERE pid = 36747
ORDER BY count DESC LIMIT 4;
pid | event_type | event | count
−−−−−−−+−−−−−−−−−−−−+−−−−−−−−−−−−−−−−+−−−−−−−
36747 | IO | WALWrite | 3603
36747 | LWLock | WALWrite | 2095
36747 | IO | WALSync | 22
36747 | IO | DataFileExtend | 19
(4 rows)


     
            
             
          
               
              
               
        

Part IV
Query Execution
16
Query Execution Stages
  
              
            
             
             
           
              
             
     
            
              
           
          
   
              
              

    booking        
       ticket  
           
       



    
      ight segments     
             
             
            
   
 ight     airport      
            
 
              routes
       
     boarding pass   
              
            
     
   seats         
         aircraft   
              

            
             
    
             
             
            
      
             
          
           
          
   en        
       

  
Bookings
# book_ref
book_date
total_amount
Airports
# airport_code
airport_name
city
coordinates
timezone
Tickets
# ticket_no
book_ref
passenger_id
passenger_name
contact_data
Ticket_ights
# ticket_no
# ight_id
fare_conditions
amount
Flights
# ight_id
ight_no
scheduled_departure
scheduled_arrival
departure_airport
arrival_airport
status
aircraft_code
actual_departure
actual_arrival
Aircrafts
# aircraft_code
model
range
Boarding_passes
# ticket_no
# ight_id
boarding_no
seat_no
Seats
# aircraft_code
# seat_no
fare_conditions
1

    
   
         
               
             
        

              

             
           
          
     
             
        
SELECT schemaname, tablename
FROM pg_tables
WHERE tableowner = 'postgres'
ORDER BY tablename;
            
            
              
           
   

  





   
QUERY
TARGETENTRY FROMEXPR
RTE
pg_tables
OPEXPR
tableowner = 'postgres'
SORTGROUPCLAUSE
SELECT
schemaname, tablename FROM ORDER BY tablename
pg_table WHERE tableowner = 'postgres'
          
             
            
          
             
            
          
           
          
  
             
        

        




    
            
               
    
        
             

             
     
SELECT schemaname, tablename
FROM (
-- pg_tables
SELECT n.nspname AS schemaname,
c.relname AS tablename,
pg_get_userbyid(c.relowner) AS tableowner,
...
FROM pg_class c
LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
LEFT JOIN pg_tablespace t ON t.oid = c.reltablespace
WHERE c.relkind = ANY (ARRAY['r'::char, 'p'::char])
)
WHERE tableowner = 'postgres'
ORDER BY tablename;
             
          
               
    
             
         
         
    




   
QUERY
TARGETENTRY FROMEXPR
RTE
pg_tables
QUERY
TARGETENTRY FROMEXPR
JOINEXPR
JOINEXPR
RTE
pg_class
RTE
pg_namespace
OPEXPR
n.oid = c.relnamespace
RTE
pg_tablespace
OPEXPR
t.oid = c.reltablespace
OPEXPR
c.relkind = ANY (ARRAY[...])
OPEXPR
tableowner = 'postgres'
SORTGROUPCLAUSE
              
             
             
                
             
           
        

    

             
 
            
             
            
               
              
              
                
             
   
            
             
   
              
       
                
            
          
             
            
         
             
              
  
             
      



   
=> EXPLAIN SELECT schemaname, tablename
FROM pg_tables
WHERE tableowner = 'postgres'
ORDER BY tablename;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Sort (cost=21.03..21.04 rows=1 width=128)
Sort Key: c.relname
−> Nested Loop Left Join (cost=0.00..21.02 rows=1 width=128)
Join Filter: (n.oid = c.relnamespace)
−> Seq Scan on pg_class c (cost=0.00..19.93 rows=1 width=72)
Filter: ((relkind = ANY ('{r,p}'::"char"[])) AND (pg_g...
−> Seq Scan on pg_namespace n (cost=0.00..1.04 rows=4 wid...
(7 rows)
               
       
PLANNEDSTMT
SORT
TARGETENTRY NESTLOOP
TARGETENTRY SEQSCAN
pg_class
OPEXPR
relkind = ANY ('r,p'::"char"[]) AND pg_get_userbyid(relowner) = 'postgres'::name
SEQSCAN
pg_namespace
OPEXPR
n.oid = c.relnamespace
         
            
             
             


    
           
              
           
          
          
  
              
            
             
           
           
         
        
         
            
             
        
               
           
SELECT ...
FROM a, b, c, d, e
WHERE ...
               
          




   
FROMEXPR
A B C D E
           
SELECT ...
FROM a, b JOIN cON ..., d, e
WHERE ...
     
FROMEXPR
A JOINEXPR
B C
D E
                
          
      
             
 8         
          
      
             
       
            
  

    
             
  
              
  
8       
           
    
   
SELECT ...
FROM a,
(
SELECT ... FROM b, c WHERE ...
) bc,
d, e
WHERE ...
             
           
FROMEXPR
A FROMEXPR
B C
D E
           
             
            
          
 on             
12            

   
         
               
            
   
          
  
             
               
             
                 
             
 
         
=> EXPLAIN
SELECT schemaname, tablename
FROM pg_tables
WHERE tableowner = 'postgres'
ORDER BY tablename;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Sort (cost=21.03..21.04 rows=1 width=128)
Sort Key: c.relname
−> Nested Loop Left Join (cost=0.00..21.02 rows=1 width=128)
Join Filter: (n.oid = c.relnamespace)
−> Seq Scan on pg_class c (cost=0.00..19.93 rows=1 width=72)
Filter: ((relkind = ANY ('{r,p}'::"char"[])) AND (pg_g...
−> Seq Scan on pg_namespace n (cost=0.00..1.04 rows=4 wid...
(7 rows)
             
            
     




    
               
       
           
            
              
        
            
 0.1          
        
      
              
                
                
            
              
             
              
              
     
          
     
             
           
           
           
 
          
    
  
  

   
            
       
              
   
           
             
               
              
         
           
            
  
            
               
             
          
      
 
 
           
         
             
             
           

            

            
          
   

    
             
   
           
                 
          
           
          
          
         
    
            
              
               
                 
        
          
              
              
             
           
            
          

          
            
             




   
SORT
NESTLOOP
SEQSCAN
pg_class
SEQSCAN
pg_namespace
               
        
             
              
          
             
            
             
              
             
              
         
              
            
   
            
              
 4MB            
         
            
             
        


    
   
             
         




               
             
       
             
           
             
             
           
              
             

         
            
 

             
        
           
              
            

   
             
            
           
             
           
              
   
=> PREPARE plane(text) AS
SELECT *FROM aircrafts WHERE aircraft_code = $1;
          
=> SELECT name, statement, parameter_types
FROM pg_prepared_statements \gx
−[ RECORD 1 ]−−−+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
name | plane
statement | PREPARE plane(text) AS +
| SELECT * FROM aircrafts WHERE aircraft_code = $1;
parameter_types | {text}
             
          
          
 
           

=> EXECUTE plane('733');
aircraft_code | model | range
−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−+−−−−−−−
733 | Boeing 737−300 | 4200
(1 row)
         
           
            

    
           
        
  
          
              
           
            
             
  
=> CREATE INDEX ON bookings(total_amount);
=> EXPLAIN SELECT *FROM bookings
WHERE total_amount > 1000000;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Bitmap Heap Scan on bookings (cost=86.49..9245.82 rows=4395 wid...
Recheck Cond: (total_amount > '1000000'::numeric)
−> Bitmap Index Scan on bookings_total_amount_idx (cost=0.00....
Index Cond: (total_amount > '1000000'::numeric)
(4 rows)
               
          
=> EXPLAIN SELECT *FROM bookings WHERE total_amount > 100;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Seq Scan on bookings (cost=0.00..39835.88 rows=2111110 width=21)
Filter: (total_amount > '100'::numeric)
(2 rows)
                
            
             
  

   
           
     
          
           
             
             
             
        
            
           
   
=> EXECUTE plane('763');
=> EXECUTE plane('773');
=> EXPLAIN EXECUTE plane('319');
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Seq Scan on aircrafts_data ml (cost=0.00..1.39 rows=1 width=52)
Filter: ((aircraft_code)::text = '319'::text)
(2 rows)
              
               
          
            
 
=> EXECUTE plane('320');
=> EXPLAIN EXECUTE plane('321');
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Seq Scan on aircrafts_data ml (cost=0.00..1.39 rows=1 width=52)
Filter: ((aircraft_code)::text = $1)
(2 rows)
  

    
            
            
             
          
            
          auto  
 
=> SET plan_cache_mode = 'force_custom_plan';
=> EXPLAIN EXECUTE plane('CN1');
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Seq Scan on aircrafts_data ml (cost=0.00..1.39 rows=1 width=52)
Filter: ((aircraft_code)::text = 'CN1'::text)
(2 rows)
          

=> SELECT name, generic_plans, custom_plans
FROM pg_prepared_statements;
name | generic_plans | custom_plans
−−−−−−−+−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−
plane | 1 | 6
(1 row)
  
            
              
           
     
=> BEGIN;
=> DECLARE cur CURSOR FOR
SELECT *
FROM aircrafts
ORDER BY aircraft_code;

   
=> FETCH 3FROM cur;
aircraft_code | model | range
−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−−+−−−−−−−
319 | Airbus A319−100 | 6700
320 | Airbus A320−200 | 5700
321 | Airbus A321−200 | 5600
(3 rows)
=> FETCH 2FROM cur;
aircraft_code | model | range
−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−+−−−−−−−
733 | Boeing 737−300 | 4200
763 | Boeing 767−300 | 7900
(2 rows)
=> COMMIT;
              
              
            
            
              
            

17
Statistics
  
           
    
     
    
         
       
=> SELECT reltuples, relpages, relallvisible
FROM pg_class WHERE relname = 'flights';
reltuples | relpages | relallvisible
−−−−−−−−−−−+−−−−−−−−−−+−−−−−−−−−−−−−−−
214867 | 2624 | 2624
(1 row)
              
 
=> EXPLAIN SELECT *FROM flights;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Seq Scan on flights (cost=0.00..4772.67 rows=214867 width=63)
(1 row)


  
           
           
           
      
   100     
           
                
          
            
       
             
             
              
       
             
    
=> CREATE TABLE flights_copy(LIKE flights)
WITH (autovacuum_enabled = false);
        
=> SELECT reltuples, relpages, relallvisible
FROM pg_class WHERE relname = 'flights_copy';
reltuples | relpages | relallvisible
−−−−−−−−−−−+−−−−−−−−−−+−−−−−−−−−−−−−−−
1 | 0 | 0
(1 row)
  
  
  
  
  
  


  
             
        
                
             
    
=> EXPLAIN SELECT *FROM flights_copy;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Seq Scan on flights_copy (cost=0.00..14.10 rows=410 width=170)
(1 row)
                
             
              
     
            
=> INSERT INTO flights_copy SELECT *FROM flights;
INSERT 0 214867
=> ANALYZE flights_copy;
             
          
=> SELECT reltuples, relpages, relallvisible
FROM pg_class WHERE relname = 'flights_copy';
reltuples | relpages | relallvisible
−−−−−−−−−−−+−−−−−−−−−−+−−−−−−−−−−−−−−−
214867 | 2624 | 0
(1 row)
               
   
=> VACUUM flights_copy;
  

  
=> SELECT relallvisible FROM pg_class WHERE relname = 'flights_copy';
relallvisible
−−−−−−−−−−−−−−−
2624
(1 row)
            
     
=> INSERT INTO flights_copy SELECT *FROM flights;
=> SELECT count(*) FROM flights_copy;
count
−−−−−−−−
429734
(1 row)
=> EXPLAIN SELECT *FROM flights_copy;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Seq Scan on flights_copy (cost=0.00..9545.34 rows=429734 width=63)
(1 row)
           
=> SELECT reltuples, relpages
FROM pg_class WHERE relname = 'flights_copy';
reltuples | relpages
−−−−−−−−−−−+−−−−−−−−−−
214867 | 2624
(1 row)
               
            
            
       
=> SELECT reltuples *
(pg_relation_size('flights_copy') / 8192) / relpages AS tuples
FROM pg_class WHERE relname = 'flights_copy';
  

  
tuples
−−−−−−−−
429734
(1 row)
             
              
          
  
          
            
     
         
            
            
            
              
             
             
      
            
              
             
        
           
       
              
     
=> EXPLAIN SELECT *FROM flights WHERE actual_departure IS NULL;



  
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Seq Scan on flights (cost=0.00..4772.67 rows=16702 width=63)
Filter: (actual_departure IS NULL)
(2 rows)
             
   
=> SELECT round(reltuples * s.null_frac) AS rows
FROM pg_class
JOIN pg_stats s ON s.tablename = relname
WHERE s.tablename = 'flights'
AND s.attname = 'actual_departure';
rows
−−−−−−−
16702
(1 row)
      
=> SELECT count(*) FROM flights WHERE actual_departure IS NULL;
count
−−−−−−−
16348
(1 row)
  
             

            
            
             
           
               
  
  

  
values
frequency
null_frac
n_distinct
             
          
            
           
=> EXPLAIN SELECT *
FROM flights
WHERE departure_airport = (
SELECT airport_code FROM airports WHERE city = 'Saint Petersburg'
);
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Seq Scan on flights (cost=30.56..5340.40 rows=2066 width=63)
Filter: (departure_airport = $0)
InitPlan 1 (returns $0)
−> Seq Scan on airports_data ml (cost=0.00..30.56 rows=1 wi...
Filter: ((city −>> lang()) = 'Saint Petersburg'::text)
(5 rows)
              
  
  

   
=> SELECT round(reltuples / s.n_distinct) AS rows
FROM pg_class
JOIN pg_stats s ON s.tablename = relname
WHERE s.tablename = 'flights'
AND s.attname = 'departure_airport';
rows
−−−−−−
2066
(1 row)
           
            
ALTER TABLE ...
ALTER COLUMN ...
SET (n_distinct = ...);
           
         
          
=> SELECT min(cnt), round(avg(cnt)) avg, max(cnt)
FROM (
SELECT departure_airport, count(*) cnt
FROM flights
GROUP BY departure_airport
) t;
min | avg | max
−−−−−+−−−−−−+−−−−−−−
113 | 2066 | 20875
(1 row)
   
           
           
        
           

  
values
frequency
null_frac
[ most_common_vals ]
[ most_common_freqs ]
=> SELECT most_common_vals AS mcv,
left(most_common_freqs::text,60) || '...' AS mcf
FROM pg_stats
WHERE tablename = 'flights' AND attname = 'aircraft_code' \gx
−[ RECORD 1 ]−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
mcv | {CN1,CR2,SU9,321,733,763,319,773}
mcf | {0.27886668,0.27266666,0.26176667,0.057166666,0.037666667,0....
           
            
      
=> EXPLAIN SELECT *FROM flights WHERE aircraft_code = '733';
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Seq Scan on flights (cost=0.00..5309.84 rows=8093 width=63)
Filter: (aircraft_code = '733'::bpchar)
(2 rows)
  

   
=> SELECT round(reltuples * s.most_common_freqs[
array_position((s.most_common_vals::text::text[]),'733')
])
FROM pg_class
JOIN pg_stats s ON s.tablename = relname
WHERE s.tablename = 'flights'
AND s.attname = 'aircraft_code';
round
−−−−−−−
8093
(1 row)
            
=> SELECT count(*) FROM flights WHERE aircraft_code = '733';
count
−−−−−−−
8263
(1 row)
             
          
             
      
             
      100     
           
             
              
  
ALTER TABLE ...
ALTER COLUMN ...
SET STATISTICS ...;
           
  

  
              
            
             
              
 
 
             
            
           

             
              
             
            
  
             
    
=> SELECT left(histogram_bounds::text,60) || '...' AS hist_bounds
FROM pg_stats s
WHERE s.tablename = 'boarding_passes' AND s.attname = 'seat_no';
hist_bounds
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
{10B,10E,10F,10F,11H,12B,13B,14B,14H,15G,16B,17B,17H,19B,19B...
(1 row)
            
           
          
  

 
values
frequency
null_frac
[ mcv ]
[ mcf ]
[ histogram_bounds ]
=> EXPLAIN SELECT *FROM boarding_passes WHERE seat_no > '30B';
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Seq Scan on boarding_passes (cost=0.00..157350.10 rows=2983242 ...
Filter: ((seat_no)::text > '30B'::text)
(2 rows)
            
   
        
     
             
               
      
            
     
=> SELECT s.null_frac FROM pg_stats s
WHERE s.tablename = 'boarding_passes' AND s.attname = 'seat_no';

  
null_frac
−−−−−−−−−−−
0
(1 row)
          
=> SELECT sum(s.most_common_freqs[
array_position((s.most_common_vals::text::text[]),v)
])
FROM pg_stats s, unnest(s.most_common_vals::text::text[]) v
WHERE s.tablename = 'boarding_passes' AND s.attname = 'seat_no'
AND v > '30B';
sum
−−−−−−−−−−−−
0.21226665
(1 row)
        
=> SELECT sum(s.most_common_freqs[
array_position((s.most_common_vals::text::text[]),v)
])
FROM pg_stats s, unnest(s.most_common_vals::text::text[]) v
WHERE s.tablename = 'boarding_passes' AND s.attname = 'seat_no';
sum
−−−−−−−−−−−−
0.67816657
(1 row)
           
         
=> SELECT round( reltuples * (
0.21226665
-- MCV share
+ (1 - 0.67816657 - 0) * (51 / 100.0)
-- histogram share
))
FROM pg_class
WHERE relname = 'boarding_passes';
round
−−−−−−−−−
2983242
(1 row)

 
values
frequency
null_frac
x
           
              
       
=> SELECT count(*) FROM boarding_passes WHERE seat_no > '30B';
count
−−−−−−−−−
2993735
(1 row)
         
             
          
=> SELECT n_distinct FROM pg_stats
WHERE tablename = 'boarding_passes' AND attname = 'seat_no';
n_distinct
−−−−−−−−−−−−
461
(1 row)
             
         

  
           
             
             

     
            
             
            
     
        
         
           
  
          
  
            
 
         
            
         
    
         











   
   
              
             
                

=> SELECT attname, avg_width FROM pg_stats
WHERE (tablename, attname) IN (VALUES
('tickets', 'passenger_name'), ('ticket_flights','fare_conditions')
);
attname | avg_width
−−−−−−−−−−−−−−−−−+−−−−−−−−−−−
fare_conditions | 8
passenger_name | 16
(2 rows)
            
   
 
            
            
              
             
            
=> SELECT attname, correlation
FROM pg_stats WHERE tablename = 'airports_data'
ORDER BY abs(correlation) DESC;
attname | correlation
−−−−−−−−−−−−−−+−−−−−−−−−−−−−
coordinates |
airport_code | −0.21120238
city | −0.1970127
airport_name | −0.18223621
timezone | 0.17961165
(5 rows)

  
             
         
         
  
               
            
          
          
      
=> EXPLAIN SELECT *FROM flights
WHERE extract(
month FROM scheduled_departure AT TIME ZONE 'Europe/Moscow'
) = 1;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Seq Scan on flights (cost=0.00..6384.17 rows=1074 width=63)
Filter: (EXTRACT(month FROM (scheduled_departure AT TIME ZONE ...
(2 rows)
=> SELECT round(reltuples * 0.005)
FROM pg_class WHERE relname = 'flights';
round
−−−−−−−
1074
(1 row)
           
           

            
  
           
          
  

  
   
            
           
     
=> CREATE STATISTICS flights_expr ON (extract(
month FROM scheduled_departure AT TIME ZONE 'Europe/Moscow'
))
FROM flights;
        
=> ANALYZE flights;
=> EXPLAIN SELECT *FROM flights
WHERE extract(
month FROM scheduled_departure AT TIME ZONE 'Europe/Moscow'
) = 1;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Seq Scan on flights (cost=0.00..6384.17 rows=16667 width=63)
Filter: (EXTRACT(month FROM (scheduled_departure AT TIME ZONE ...
(2 rows)
             
          
           
    
=> ALTER STATISTICS flights_expr SET STATISTICS 42;
            
            
          
  
          
     



  
=> SELECT left(expr,50) || '...' AS expr,
null_frac, avg_width, n_distinct,
most_common_vals AS mcv,
left(most_common_freqs::text,50) || '...' AS mcf,
correlation
FROM pg_stats_ext_exprs
WHERE statistics_name = 'flights_expr' \gx
−[ RECORD 1 ]−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
expr | EXTRACT(month FROM (scheduled_departure AT TIME ZO...
null_frac | 0
avg_width | 8
n_distinct | 12
mcv | {8,9,12,3,1,5,6,7,11,10,4,2}
mcf | {0.12053333,0.11326667,0.0802,0.07976667,0.0775666...
correlation | 0.08355749
   
           
           
                
      
=> DROP STATISTICS flights_expr;
=> CREATE INDEX ON flights(extract(
month FROM scheduled_departure AT TIME ZONE 'Europe/Moscow'
));
=> ANALYZE flights;
=> EXPLAIN SELECT *FROM flights
WHERE extract(
month FROM scheduled_departure AT TIME ZONE 'Europe/Moscow'
) = 1;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Bitmap Heap Scan on flights (cost=324.86..3247.92 rows=17089 wi...
Recheck Cond: (EXTRACT(month FROM (scheduled_departure AT TIME...
−> Bitmap Index Scan on flights_extract_idx (cost=0.00..320.5...
Index Cond: (EXTRACT(month FROM (scheduled_departure AT TI...
(4 rows)

  
             
            
     
=> SELECT n_distinct FROM pg_stats
WHERE tablename = 'flights_extract_idx';
n_distinct
−−−−−−−−−−−−
12
(1 row)
            
             
         
=> SELECT attname FROM pg_attribute
WHERE attrelid = 'flights_extract_idx'::regclass;
attname
−−−−−−−−−
extract
(1 row)
=> ALTER INDEX flights_extract_idx
ALTER COLUMN extract SET STATISTICS 42;
  
            
          
     
      
    
             
           


  
      
=> SELECT count(*) FROM flights
WHERE flight_no = 'PG0007' AND departure_airport = 'VKO';
count
−−−−−−−
396
(1 row)
    
=> EXPLAIN SELECT *FROM flights
WHERE flight_no = 'PG0007' AND departure_airport = 'VKO';
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Bitmap Heap Scan on flights (cost=10.49..816.84 rows=15 width=63)
Recheck Cond: (flight_no = 'PG0007'::bpchar)
Filter: (departure_airport = 'VKO'::bpchar)
−> Bitmap Index Scan on flights_flight_no_scheduled_departure_key
(cost=0.00..10.49 rows=276 width=0)
Index Cond: (flight_no = 'PG0007'::bpchar)
(6 rows)
           
              
            
            
            
            

           
            
            
    
           

=> CREATE STATISTICS flights_dep(dependencies)
ON flight_no, departure_airport FROM flights;

  
          
=> ANALYZE flights;
=> EXPLAIN SELECT *FROM flights
WHERE flight_no = 'PG0007'
AND departure_airport = 'VKO';
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Bitmap Heap Scan on flights (cost=10.57..819.51 rows=277 width=63)
Recheck Cond: (flight_no = 'PG0007'::bpchar)
Filter: (departure_airport = 'VKO'::bpchar)
−> Bitmap Index Scan on flights_flight_no_scheduled_departure_key
(cost=0.00..10.50 rows=277 width=0)
Index Cond: (flight_no = 'PG0007'::bpchar)
(6 rows)
              
=> SELECT dependencies
FROM pg_stats_ext WHERE statistics_name = 'flights_dep';
dependencies
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
{"2 => 5": 1.000000, "5 => 2": 0.010200}
(1 row)
           
           
             

      
           
         
 
            
              
          

  
=> SELECT count(*)
FROM (
SELECT DISTINCT departure_airport, arrival_airport FROM flights
) t;
count
−−−−−−−
618
(1 row)
=> EXPLAIN SELECT DISTINCT departure_airport, arrival_airport
FROM flights;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
HashAggregate (cost=5847.01..5955.16 rows=10816 width=8)
Group Key: departure_airport, arrival_airport
−> Seq Scan on flights (cost=0.00..4772.67 rows=214867 width=8)
(3 rows)
         
=> CREATE STATISTICS flights_nd(ndistinct)
ON departure_airport, arrival_airport FROM flights;
=> ANALYZE flights;
    
=> EXPLAIN SELECT DISTINCT departure_airport, arrival_airport
FROM flights;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
HashAggregate (cost=5847.01..5853.19 rows=618 width=8)
Group Key: departure_airport, arrival_airport
−> Seq Scan on flights (cost=0.00..4772.67 rows=214867 width=8)
(3 rows)
         
=> SELECT n_distinct
FROM pg_stats_ext WHERE statistics_name = 'flights_nd';
n_distinct
−−−−−−−−−−−−−−−
{"5, 6": 618}
(1 row)

  
   
               
          
           
      
=> SELECT count(*) FROM flights
WHERE departure_airport = 'SVO' AND aircraft_code = '733';
count
−−−−−−−
2037
(1 row)
=> EXPLAIN SELECT *FROM flights
WHERE departure_airport = 'SVO' AND aircraft_code = '733';
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Seq Scan on flights (cost=0.00..5847.00 rows=736 width=63)
Filter: ((departure_airport = 'SVO'::bpchar) AND (aircraft_cod...
(2 rows)
            
 
=> CREATE STATISTICS flights_mcv(mcv)
ON departure_airport, aircraft_code FROM flights;
=> ANALYZE flights;
       
=> EXPLAIN SELECT *FROM flights
WHERE departure_airport = 'SVO' AND aircraft_code = '733';
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Seq Scan on flights (cost=0.00..5847.00 rows=1927 width=63)
Filter: ((departure_airport = 'SVO'::bpchar) AND (aircraft_cod...
(2 rows)



  
            
 
=> SELECT values, frequency
FROM pg_statistic_ext stx
JOIN pg_statistic_ext_data stxd ON stx.oid = stxd.stxoid,
pg_mcv_list_items(stxdmcv) m
WHERE stxname = 'flights_mcv'
AND values = '{SVO,773}';
values | frequency
−−−−−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−
{SVO,773} | 0.005266666666666667
(1 row)
       100  
                
                 
 
ALTER STATISTICS ... SET STATISTICS ...;
             
       
           
             
           
            
    

18
Table Access Methods
   
              
            
            
         
=> SELECT amname, amhandler FROM pg_am WHERE amtype = 't';
amname | amhandler
−−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−
heap | heap_tableam_handler
(1 row)
            
       heap 
  
              
         
         
    
          
       
 



    
 

  
 
              
  
    
    
     
       
 
   
          
               
             
 
                 
              
               
              
              
   
             
             
              
           
            



  
             
 
          
          
          
           
            
      
          
 
              
              
          
  
             
             
                 
             
table page
a tuple
to be ltered out



    
             
           
             
            
     
              
              
               
         
 
             
=> EXPLAIN SELECT *
FROM flights;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Seq Scan on flights (cost=0.00..4772.67 rows=214867 width=63)
(1 row)
            
=> SELECT reltuples FROM pg_class WHERE relname = 'flights';
reltuples
−−−−−−−−−−−
214867
(1 row)
           
     
              
           
  

  
          
             
            
        1 
        4 
              
        
             
           
     
=> SELECT relpages,
current_setting('seq_page_cost') AS seq_page_cost,
relpages * current_setting('seq_page_cost')::real AS total
FROM pg_class WHERE relname = 'flights';
relpages | seq_page_cost | total
−−−−−−−−−−+−−−−−−−−−−−−−−−+−−−−−−−
2624 | 1 | 2624
(1 row)
          
            
            
           
   0.01
=> SELECT reltuples,
current_setting('cpu_tuple_cost') AS cpu_tuple_cost,
reltuples * current_setting('cpu_tuple_cost')::real AS total
FROM pg_class WHERE relname = 'flights';
reltuples | cpu_tuple_cost | total
−−−−−−−−−−−+−−−−−−−−−−−−−−−−+−−−−−−−−−
214867 | 0.01 | 2148.67
(1 row)
             
         

    
             
               
           
   
           
         
=> EXPLAIN (analyze, timing off, summary off)
SELECT *FROM flights
WHERE status = 'Scheduled';
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Seq Scan on flights
(cost=0.00..5309.84 rows=15383 width=63)
(actual rows=15383 loops=1)
Filter: ((status)::text = 'Scheduled'::text)
Rows Removed by Filter: 199484
(5 rows)
          
=> EXPLAIN SELECT count(*) FROM seats;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Aggregate (cost=24.74..24.75 rows=1 width=8)
−> Seq Scan on seats (cost=0.00..21.39 rows=1339 width=0)
(2 rows)
            
             

             
               
              
      0.0025   
 
  

  
=> SELECT reltuples,
current_setting('cpu_operator_cost') AS cpu_operator_cost,
round((
reltuples * current_setting('cpu_operator_cost')::real
)::numeric, 2) AS cpu_cost
FROM pg_class WHERE relname = 'seats';
reltuples | cpu_operator_cost | cpu_cost
−−−−−−−−−−−+−−−−−−−−−−−−−−−−−−−+−−−−−−−−−−
1339 | 0.0025 | 3.35
(1 row)
             
              
      0.01
=> WITH t(cpu_cost) AS (
SELECT round((
reltuples * current_setting('cpu_operator_cost')::real
)::numeric, 2)
FROM pg_class WHERE relname = 'seats'
)
SELECT 21.39 + t.cpu_cost AS startup_cost,
round((
21.39 + t.cpu_cost +
1 * current_setting('cpu_tuple_cost')::real
)::numeric, 2) AS total_cost
FROM t;
startup_cost | total_cost
−−−−−−−−−−−−−−+−−−−−−−−−−−−
24.74 | 24.75
(1 row)
        
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Aggregate
(cost=24.74..24.75 rows=1 width=8)
−> Seq Scan on seats
(cost=0.00..21.39 rows=1339 width=0)
(4 rows)

    
  
         
           
             
           
              

             
   on  
parallel
part of the plan
parallel
part of the plan
Gather
sequential
part of the plan
parallel
part of the plan
worker workerleader
            
      
             
            
  




   
            
             
           
     
   
             
    
            
               
            
          
           
       
              
           
          
         
         
             
             
           
            
 
            
   
  
 

    
=> EXPLAIN SELECT count(*) FROM bookings;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Finalize Aggregate (cost=25442.58..25442.59 rows=1 width=8)
−> Gather (cost=25442.36..25442.57 rows=2 width=8)
Workers Planned: 2
−> Partial Aggregate
(cost=24442.36..24442.37 rows=1 width=8)
−> Parallel Seq Scan on bookings
(cost=0.00..22243.29 rows=879629 width=0)
(7 rows)
               
              
        
             
           
            
              
           
              
         
=> SELECT reltuples::numeric, round(reltuples / 2.4) AS per_process
FROM pg_class WHERE relname = 'bookings';
reltuples | per_process
−−−−−−−−−−−+−−−−−−−−−−−−−
2111110 | 879629
(1 row)
              
              
             
=> SELECT round((
relpages * current_setting('seq_page_cost')::real +
reltuples / 2.4 * current_setting('cpu_tuple_cost')::real
)::numeric, 2)
FROM pg_class WHERE relname = 'bookings';
  

   
round
−−−−−−−−−−
22243.29
(1 row)
            
       
              
    
=> WITH t(startup_cost)
AS (
SELECT 22243.29 + round((
reltuples / 2.4 * current_setting('cpu_operator_cost')::real
)::numeric, 2)
FROM pg_class
WHERE relname = 'bookings'
)
SELECT startup_cost,
startup_cost + round((
1 * current_setting('cpu_tuple_cost')::real
)::numeric, 2) AS total_cost
FROM t;
startup_cost | total_cost
−−−−−−−−−−−−−−+−−−−−−−−−−−−
24442.36 | 24442.37
(1 row)
            
        
           
       1000     
         0.1
            
               
               
   
  

    
=> SELECT
24442.36 + round(
current_setting('parallel_setup_cost')::numeric,
2) AS setup_cost,
24442.37 + round(
current_setting('parallel_setup_cost')::numeric +
2 * current_setting('parallel_tuple_cost')::numeric,
2) AS total_cost;
setup_cost | total_cost
−−−−−−−−−−−−+−−−−−−−−−−−−
25442.36 | 25442.57
(1 row)
            
       
              
               
              
        
=> WITH t(startup_cost) AS (
SELECT 25442.57 + round((
3 * current_setting('cpu_operator_cost')::real
)::numeric, 2)
FROM pg_class WHERE relname = 'bookings'
)
SELECT startup_cost,
startup_cost + round((
1 * current_setting('cpu_tuple_cost')::real
)::numeric, 2) AS total_cost
FROM t;
startup_cost | total_cost
−−−−−−−−−−−−−−+−−−−−−−−−−−−
25442.58 | 25442.59
(1 row)
          
            
                
               
              
               
     

   
    
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Finalize Aggregate
(cost=25442.58..25442.59 rows=1 width=8)
−> Gather
(cost=25442.36..25442.57 rows=2 width=8)
Workers Planned: 2
−> Partial Aggregate
(cost=24442.36..24442.37 rows=1 width=8)
−> Parallel Seq Scan on bookings
(cost=0.00..22243.29 rows=879629 width=0)
(9 rows)
   
   
          
         
8 
           
            
           
     8 
      2    

          
          

       
          


    
           
             
        8MB  
            
          
 

            
           


 






              
 
               
=> EXPLAIN (analyze, costs off, timing off, summary off)
SELECT count(*) FROM flights;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Finalize Aggregate (actual rows=1 loops=1)
−> Gather (actual rows=2 loops=1)
Workers Planned: 1
Workers Launched: 1
−> Partial Aggregate (actual rows=1 loops=2)
−> Parallel Seq Scan on flights (actual rows=107434 lo...
(6 rows)

   
               
2 
=> EXPLAIN (analyze, costs off, timing off, summary off)
SELECT count(*) FROM bookings;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Finalize Aggregate (actual rows=1 loops=1)
−> Gather (actual rows=3 loops=1)
Workers Planned: 2
Workers Launched: 2
−> Partial Aggregate (actual rows=1 loops=3)
−> Parallel Seq Scan on bookings (actual rows=703703 l...
(6 rows)
           
=> ALTER SYSTEM SET max_parallel_workers_per_gather = 4;
=> SELECT pg_reload_conf();
=> EXPLAIN (analyze, costs off, timing off, summary off)
SELECT count(*) FROM bookings;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Finalize Aggregate (actual rows=1 loops=1)
−> Gather (actual rows=4 loops=1)
Workers Planned: 3
Workers Launched: 3
−> Partial Aggregate (actual rows=1 loops=4)
−> Parallel Seq Scan on bookings (actual rows=527778 l...
(6 rows)
               
            
              

=> ALTER SYSTEM SET max_parallel_workers = 5;
=> SELECT pg_reload_conf();
=> EXPLAIN (analyze, costs off, timing off, summary off)
SELECT count(*) FROM bookings;

    
=> EXPLAIN (analyze, costs off, timing off, summary off)
SELECT count(*) FROM bookings;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Finalize Aggregate (actual rows=1 loops=1)
−> Gather (actual rows=3 loops=1)
Workers Planned: 3
Workers Launched: 2
−> Partial Aggregate (actual rows=1 loops=3)
−> Parallel Seq Scan on bookings (actual rows=7037...
(6 rows)
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Finalize Aggregate (actual rows=1 loops=1)
−> Gather (actual rows=4 loops=1)
Workers Planned: 3
Workers Launched: 3
−> Partial Aggregate (actual rows=1 loops=4)
−> Parallel Seq Scan on bookings (actual rows=527778 l...
(6 rows)
            
    
    
=> ALTER SYSTEM RESET ALL;
=> SELECT pg_reload_conf();
 
            
   
          



   
          
      
    
          
            
   
           
             
     
SELECT *FROM pg_proc WHERE proparallel = 'u';
          
        
            
            
 
             

      
         
          
      
       
           
  off        
 




    
=> EXPLAIN SELECT *FROM flights;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Seq Scan on flights (cost=0.00..4772.67 rows=214867 width=63)
(1 row)
=> SET force_parallel_mode = on;
=> EXPLAIN SELECT *FROM flights;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Gather (cost=1000.00..27259.37 rows=214867 width=63)
Workers Planned: 1
Single Copy: true
−> Seq Scan on flights (cost=0.00..4772.67 rows=214867 width=63)
(4 rows)
  
               
        
           
               
        
            
=> EXPLAIN (costs off)
WITH tAS MATERIALIZED (
SELECT *FROM flights
)
SELECT count(*) FROM t;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Aggregate
CTE t
−> Seq Scan on flights
−> CTE Scan on t
(4 rows)



   
                
   
               
   
=> EXPLAIN (costs off)
WITH tAS MATERIALIZED (
SELECT count(*) FROM flights
)
SELECT *FROM t;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
CTE Scan on t
CTE t
−> Finalize Aggregate
−> Gather
Workers Planned: 1
−> Partial Aggregate
−> Parallel Seq Scan on flights
(7 rows)
         
    
=> EXPLAIN (costs off)
SELECT *FROM flights f
WHERE f.scheduled_departure > (
-- SubPlan
SELECT min(f2.scheduled_departure)
FROM flights f2
WHERE f2.aircraft_code = f.aircraft_code
);
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Seq Scan on flights f
Filter: (scheduled_departure > (SubPlan 1))
SubPlan 1
−> Aggregate
−> Seq Scan on flights f2
Filter: (aircraft_code = f.aircraft_code)
(6 rows)
               
             

    
             
            
   
             
          
            
 
=> EXPLAIN (costs off)
SELECT *FROM flights f
WHERE f.scheduled_departure > (
-- SubPlan
SELECT min(f2.scheduled_departure)
FROM flights f2
WHERE EXISTS (
-- InitPlan
SELECT *
FROM ticket_flights tf
WHERE tf.flight_id = f.flight_id
)
);
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Seq Scan on flights f
Filter: (scheduled_departure > (SubPlan 2))
SubPlan 2
−> Finalize Aggregate
InitPlan 1 (returns $1)
−> Seq Scan on ticket_flights tf
Filter: (flight_id = f.flight_id)
−> Gather
Workers Planned: 1
Params Evaluated: $1
−> Partial Aggregate
−> Result
One−Time Filter: $1
−> Parallel Seq Scan on flights f2
(14 rows)
            
       
           
             

   
           
             
              
            
     
=> CREATE TEMPORARY TABLE flights_tmp AS SELECT *FROM flights;
=> EXPLAIN (costs off)
SELECT count(*) FROM flights_tmp;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Aggregate
−> Seq Scan on flights_tmp
(2 rows)
         
                
       
SELECT *FROM pg_proc WHERE proparallel = 'r';
            
               
 


19
Index Access Methods
   
            
            
              
  
          
=> SELECT amname FROM pg_am WHERE amtype = 'i';
amname
−−−−−−−−
btree
hash
gist
gin
spgist
brin
(6 rows)
           
            
   
           
              
              
               
          

   
            
           
     
      
      
         
            
           
           
               
               
      
               
           
      
             
           
  
        
          
 
           
   
      
       
    
    
   

    
             
           
         
             
          
            
       
           
            
             
           
             
              
 
       
Indexing
engine
btree
bool_ops boolean
int4_ops integer
text_ops
text
text_pattern_ops
gist
gist_int4_ops
gist_text_ops
point_ops point
access methods operator classes data types

    
    
 
          
           

             
         
=> SELECT amname, opcname, opcintype::regtype
FROM pg_am am
JOIN pg_opclass opc ON opcmethod = am.oid;
amname | opcname | opcintype
−−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
btree | array_ops | anyarray
hash | array_ops | anyarray
btree | bit_ops | bit
btree | bool_ops | boolean
...
brin | pg_lsn_minmax_multi_ops | pg_lsn
brin | pg_lsn_bloom_ops | pg_lsn
brin | box_inclusion_ops | box
(177 rows)
             
        
              
       
=> SELECT opcname, opcdefault
FROM pg_am am
JOIN pg_opclass opc ON opcmethod = am.oid
WHERE amname = 'btree'
AND opcintype = 'text'::regtype;



    
opcname | opcdefault
−−−−−−−−−−−−−−−−−−−−−+−−−−−−−−−−−−
text_ops | t
varchar_ops | f
text_pattern_ops | f
varchar_pattern_ops | f
(4 rows)
       
CREATE INDEX ON aircrafts(model, range);
           
CREATE INDEX ON aircrafts
USING btree
-- the default access method
(
model text_ops,
-- the default operator class for text
range int4_ops
-- the default operator class for integer
);
               
            
           
            
    
          
         
=> SELECT opcname, amopstrategy, amopopr::regoperator
FROM pg_am am
JOIN pg_opfamily opf ON opfmethod = am.oid
JOIN pg_opclass opc ON opcfamily = opf.oid
JOIN pg_amop amop ON amopfamily = opcfamily
WHERE amname = 'btree'
AND opcname IN ('text_ops', 'text_pattern_ops')
AND amoplefttype = 'text'::regtype
AND amoprighttype = 'text'::regtype
ORDER BY opcname, amopstrategy;

    
opcname | amopstrategy | amopopr
−−−−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−−
text_ops | 1 | <(text,text)
text_ops | 2 | <=(text,text)
text_ops | 3 | =(text,text)
text_ops | 4 | >=(text,text)
text_ops | 5 | >(text,text)
text_pattern_ops | 1 | ~<~(text,text)
text_pattern_ops | 2 | ~<=~(text,text)
text_pattern_ops | 3 | =(text,text)
text_pattern_ops | 4 | ~>=~(text,text)
text_pattern_ops | 5 | ~>~(text,text)
(10 rows)
              
          
             
 
           
             
         
     
           
             
            
=> SHOW lc_collate;
lc_collate
−−−−−−−−−−−−−
en_US.UTF−8
(1 row)
=> CREATE INDEX ON tickets(passenger_name);
=> EXPLAIN (costs off)
SELECT *FROM tickets WHERE passenger_name LIKE 'ELENA%';




    
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Seq Scan on tickets
Filter: (passenger_name ~~ 'ELENA%'::text)
(2 rows)
        
=> CREATE INDEX tickets_passenger_name_pattern_idx
ON tickets(passenger_name text_pattern_ops);
=> EXPLAIN (costs off)
SELECT *FROM tickets WHERE passenger_name LIKE 'ELENA%';
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Bitmap Heap Scan on tickets
Filter: (passenger_name ~~ 'ELENA%'::text)
−> Bitmap Index Scan on tickets_passenger_name_pattern_idx
Index Cond: ((passenger_name ~>=~ 'ELENA'::text) AND
(passenger_name ~<~ 'ELENB'::text))
(5 rows)
             
           
             
            
            
            
          
              
  
          
         
    
           
   


  

    
        
=> EXPLAIN (costs off)
SELECT *FROM tickets WHERE 'ELENA BELOVA' = passenger_name;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Index Scan using tickets_passenger_name_idx on tickets
Index Cond: (passenger_name = 'ELENA BELOVA'::text)
(2 rows)
             
              
             
     
             
         
=> EXPLAIN (costs off)
SELECT *FROM tickets WHERE initcap(passenger_name) = 'Elena Belova';
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Seq Scan on tickets
Filter: (initcap(passenger_name) = 'Elena Belova'::text)
(2 rows)
           
     
=> CREATE INDEX ON tickets( (initcap(passenger_name)) );
=> EXPLAIN (costs off)
SELECT *FROM tickets WHERE initcap(passenger_name) = 'Elena Belova';
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Bitmap Heap Scan on tickets
Recheck Cond: (initcap(passenger_name) = 'Elena Belova'::text)
−> Bitmap Index Scan on tickets_initcap_idx
Index Cond: (initcap(passenger_name) = 'Elena Belova'::text)
(4 rows)
             
           


    
            
          
             

          
            
          
     
=> SELECT amprocnum, amproc::regproc
FROM pg_am am
JOIN pg_opfamily opf ON opfmethod = am.oid
JOIN pg_opclass opc ON opcfamily = opf.oid
JOIN pg_amproc amproc ON amprocfamily = opcfamily
WHERE amname = 'btree'
AND opcname = 'text_ops'
AND amproclefttype = 'text'::regtype
AND amprocrighttype = 'text'::regtype
ORDER BY amprocnum;
amprocnum | amproc
−−−−−−−−−−−+−−−−−−−−−−−−−−−−−−−−
1 | bttextcmp
2 | bttextsortsupport
4 | btvarstrequalimage
(3 rows)
 
           
           
      
           
        





    
=> SELECT opcname, opcintype::regtype
FROM pg_am am
JOIN pg_opfamily opf ON opfmethod = am.oid
JOIN pg_opclass opc ON opcfamily = opf.oid
WHERE amname = 'btree'
AND opfname = 'integer_ops';
opcname | opcintype
−−−−−−−−−−+−−−−−−−−−−−
int2_ops | smallint
int4_ops | integer
int8_ops | bigint
(3 rows)
        
=> SELECT opcname, opcintype::regtype
FROM pg_am am
JOIN pg_opfamily opf ON opfmethod = am.oid
JOIN pg_opclass opc ON opcfamily = opf.oid
WHERE amname = 'btree'
AND opfname = 'datetime_ops';
opcname | opcintype
−−−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
date_ops | date
timestamptz_ops | timestamp with time zone
timestamp_ops | timestamp without time zone
(3 rows)
           
     
=> SELECT opcname, amopopr::regoperator
FROM pg_am am
JOIN pg_opfamily opf ON opfmethod = am.oid
JOIN pg_opclass opc ON opcfamily = opf.oid
JOIN pg_amop amop ON amopfamily = opcfamily
WHERE amname = 'btree'
AND opfname = 'integer_ops'
AND amoplefttype = 'integer'::regtype
AND amopstrategy = 1
ORDER BY opcname;

    
opcname | amopopr
−−−−−−−−−−+−−−−−−−−−−−−−−−−−−−−−
int2_ops | <(integer,bigint)
int2_ops | <(integer,smallint)
int2_ops | <(integer,integer)
int4_ops | <(integer,bigint)
int4_ops | <(integer,smallint)
int4_ops | <(integer,integer)
int8_ops | <(integer,bigint)
int8_ops | <(integer,smallint)
int8_ops | <(integer,integer)
(9 rows)
            
             
 
   
              
         
=> SELECT amname, amhandler FROM pg_am WHERE amtype = 'i';
amname | amhandler
−−−−−−−−+−−−−−−−−−−−−−
btree | bthandler
hash | hashhandler
gist | gisthandler
gin | ginhandler
spgist | spghandler
brin | brinhandler
(6 rows)
          
            
             
           



   
      
  
   
    
          
             
        
  
             
  
=> SELECT a.amname, p.name, pg_indexam_has_property(a.oid, p.name)
FROM pg_am a, unnest(array[
'can_order', 'can_unique', 'can_multi_col',
'can_exclude', 'can_include'
]) p(name)
WHERE a.amname = 'btree';
amname | name | pg_indexam_has_property
−−−−−−−−+−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−−−
btree | can_order | t
btree | can_unique | t
btree | can_multi_col | t
btree | can_exclude | t
btree | can_include | t
(5 rows)
           
  
              
   
  


    
=> EXPLAIN (costs off)
SELECT *FROM seats ORDER BY seat_no;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−
Sort
Sort Key: seat_no
−> Seq Scan on seats
(3 rows)
              
     
=> EXPLAIN (costs off)
SELECT *FROM seats ORDER BY aircraft_code;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Index Scan using seats_pkey on seats
(1 row)
          
   
          
       
=> INSERT INTO bookings(book_ref, book_date, total_amount)
VALUES ('000004', now(), 100.00);
ERROR: duplicate key value violates unique constraint
"bookings_pkey"
DETAIL: Key (book_ref)=(000004) already exists.
           
            
         
           
            
   
          
            


   
           
           
  
        
         
         
            
=> \d ticket_flights_pkey
Index "bookings.ticket_flights_pkey"
Column | Type | Key? | Definition
−−−−−−−−−−−+−−−−−−−−−−−−−−−+−−−−−−+−−−−−−−−−−−−
ticket_no | character(13) | yes | ticket_no
flight_id | integer | yes | flight_id
primary key, btree, for table "bookings.ticket_flights"
           
=> EXPLAIN (costs off)
SELECT *FROM ticket_flights
WHERE ticket_no = '0005432001355'
AND flight_id = 51618;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Index Scan using ticket_flights_pkey on ticket_flights
Index Cond: ((ticket_no = '0005432001355'::bpchar) AND
(flight_id = 51618))
(3 rows)
           
              
            
  
=> EXPLAIN (costs off)
SELECT *
FROM ticket_flights
WHERE ticket_no = '0005432001355';


    
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Index Scan using ticket_flights_pkey on ticket_flights
Index Cond: (ticket_no = '0005432001355'::bpchar)
(2 rows)
            
             
           
          
     
         
            
           
       
            
            
            
           
             
            
           
        
               
 
          
             
         
=> CREATE UNIQUE INDEX ON flights(flight_id) INCLUDE (status);
=> EXPLAIN (costs off)
SELECT status FROM flights
WHERE flight_id = 51618;


   
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Index Only Scan using flights_flight_id_status_idx on flights
Index Cond: (flight_id = 51618)
(2 rows)
 
            
=> SELECT p.name, pg_index_has_property('seats_pkey', p.name)
FROM unnest(array[
'clusterable', 'index_scan', 'bitmap_scan', 'backward_scan'
]) p(name);
name | pg_index_has_property
−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−
clusterable | t
index_scan | t
bitmap_scan | t
backward_scan | t
(4 rows)
            
            
        
      
           
           
      
          
     
             
    
           

    
 
        
=> SELECT p.name,
pg_index_column_has_property('seats_pkey', 1, p.name)
FROM unnest(array[
'asc', 'desc', 'nulls_first', 'nulls_last', 'orderable',
'distance_orderable', 'returnable', 'search_array', 'search_nulls'
]) p(name);
name | pg_index_column_has_property
−−−−−−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
asc | t
desc | f
nulls_first | f
nulls_last | t
orderable | t
distance_orderable | f
returnable | t
search_array | t
search_nulls | t
(9 rows)
        
          
            
         
           
      
     
 
         
           
           

            
     


   
=> CREATE INDEX ON airports_data USING gist(coordinates);
=> EXPLAIN (costs off)
SELECT *FROM airports
ORDER BY coordinates <-> point (43.578,57.593)
LIMIT 3;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Limit
−> Index Scan using airports_data_coordinates_idx on airpo...
Order By: (coordinates <−> '(43.578,57.593)'::point)
(3 rows)
             

         
            
             
  
         
               
           
=> EXPLAIN (costs off)
SELECT *FROM bookings
WHERE book_ref IN ('C7C821', 'A5D060', 'DDE1BB');
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Index Scan using bookings_pkey on bookings
Index Cond: (book_ref = ANY
('{C7C821,A5D060,DDE1BB}'::bpchar[]))
(3 rows)
             
           
  
          
              
              

    
              
             
           
           
       
              
          
=> CREATE INDEX ON flights(actual_arrival)
WHERE actual_arrival IS NOT NULL;
=> EXPLAIN (costs off)
SELECT *FROM flights
WHERE actual_arrival = '2017-06-13 10:33:00+03';
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Index Scan using flights_actual_arrival_idx on flights
Index Cond: (actual_arrival = '2017−06−13 10:33:00+03'::ti...
(2 rows)
              
          
           
       
            
      
           
              
             
           
     


20
Index Scans
   
              
               
         
         
=> EXPLAIN SELECT *FROM bookings
WHERE book_ref = '9AC0C6' AND total_amount = 48500.00;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Index Scan using bookings_pkey on bookings
(cost=0.43..8.45 rows=1 width=21)
Index Cond: (book_ref = '9AC0C6'::bpchar)
Filter: (total_amount = 48500.00)
(4 rows)
           
              
            
              
    
             
             
    

  

   
           
             
              

=> EXPLAIN SELECT *FROM bookings WHERE ctid = '(0,1)'::tid;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Tid Scan on bookings (cost=0.00..4.01 rows=1 width=21)
TID Cond: (ctid = '(0,1)'::tid)
(2 rows)
 
            
    
           
           
              
              
             
           
              
  
             
              
            
              
   

  


   
   
              
                
            
heap
page
a tuple
matching
lter conditions
      
=> SELECT attname, correlation
FROM pg_stats WHERE tablename = 'bookings'
ORDER BY abs(correlation) DESC;
attname | correlation
−−−−−−−−−−−−−−+−−−−−−−−−−−−−−
book_ref | 1
total_amount | 0.0026738467
book_date | 8.02188e−05
(3 rows)
             
               

              
               
                
        

   
             
              
                  
             
                
      
             
=> EXPLAIN SELECT *FROM bookings WHERE book_ref < '100000';
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Index Scan using bookings_pkey on bookings
(cost=0.43..4638.91 rows=132999 width=21)
Index Cond: (book_ref < '100000'::bpchar)
(3 rows)
      
=> SELECT round(132999::numeric/reltuples::numeric, 4)
FROM pg_class WHERE relname = 'bookings';
round
−−−−−−−−
0.0630
(1 row)
     
         
    
             
           
               
              
           
               
      0.005    
             
       0.0025  

   
             
              
             
           
    0.01   
=> WITH costs(idx_cost, tbl_cost) AS (
SELECT
(
SELECT round(
current_setting('random_page_cost')::real * pages +
current_setting('cpu_index_tuple_cost')::real * tuples +
current_setting('cpu_operator_cost')::real * tuples
)
FROM (
SELECT relpages * 0.0630 AS pages, reltuples * 0.0630 AS tuples
FROM pg_class WHERE relname = 'bookings_pkey'
) c
),
(
SELECT round(
current_setting('seq_page_cost')::real * pages +
current_setting('cpu_tuple_cost')::real * tuples
)
FROM (
SELECT relpages * 0.0630 AS pages, reltuples * 0.0630 AS tuples
FROM pg_class WHERE relname = 'bookings'
) c
)
)
SELECT idx_cost, tbl_cost, idx_cost + tbl_cost AS total
FROM costs;
idx_cost | tbl_cost | total
−−−−−−−−−−+−−−−−−−−−−+−−−−−−−
2457 | 2177 | 4634
(1 row)
            
           
            
     

   
   
             
             
              
                
    
=> CREATE INDEX ON bookings(book_date);
=> SET enable_seqscan = off;
=> SET enable_bitmapscan = off;
=> EXPLAIN SELECT *FROM bookings
WHERE book_date < '2016-08-23 12:00:00+03';
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Index Scan using bookings_book_date_idx on bookings
(cost=0.43..56957.48 rows=132403 width=21)
Index Cond: (book_date < '2016−08−23 12:00:00+03'::timestamp w...
(3 rows)
             
             
            
            
         
             
           

   
=> WITH costs(idx_cost, tbl_cost) AS (
SELECT
(SELECT round(
current_setting('random_page_cost')::real * pages +
current_setting('cpu_index_tuple_cost')::real * tuples +
current_setting('cpu_operator_cost')::real * tuples
)
FROM (
SELECT relpages * 0.0630 AS pages, reltuples * 0.0630 AS tuples
FROM pg_class WHERE relname = 'bookings_pkey'
) c
),
(SELECT round(
current_setting('random_page_cost')::real * tuples +
current_setting('cpu_tuple_cost')::real * tuples
)
FROM (
SELECT relpages * 0.0630 AS pages, reltuples * 0.0630 AS tuples
FROM pg_class WHERE relname = 'bookings'
) c
)
)
SELECT idx_cost, tbl_cost, idx_cost + tbl_cost AS total FROM costs;
idx_cost | tbl_cost | total
−−−−−−−−−−+−−−−−−−−−−+−−−−−−−−
2457 | 533330 | 535787
(1 row)
            
                 
               
           4GB
            
            
             
  
            
               
             
  

   
table size
page
access
count
effective_cache_size
0.5 of row count
sel
= 0.5
page count
0.5 of page count
            
             
             
              
    
            
         
=> SET effective_cache_size = '8kB';
=> EXPLAIN SELECT *FROM bookings
WHERE book_date < '2016-08-23 12:00:00+03';
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Index Scan using bookings_book_date_idx on bookings
(cost=0.43..532745.48 rows=132403 width=21)
Index Cond: (book_date < '2016−08−23 12:00:00+03'::timestamp w...
(3 rows)

  
=> RESET effective_cache_size;
=> RESET enable_seqscan;
=> RESET enable_bitmapscan;
            
           
                 
             
             
         
  
              
              
             
               
       
           
=> EXPLAIN SELECT book_ref FROM bookings WHERE book_ref < '100000';
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Index Only Scan using bookings_pkey on bookings
(cost=0.43..3791.91 rows=132999 width=7)
Index Cond: (book_ref < '100000'::bpchar)
(3 rows)
                
             
              
  



   
            
 
              
             
             
             
            
             
            
       
=> SELECT relpages, relallvisible
FROM pg_class WHERE relname = 'bookings';
relpages | relallvisible
−−−−−−−−−−+−−−−−−−−−−−−−−−
13447 | 13446
(1 row)
             
               
             
  
            
          
=> WITH costs(idx_cost, tbl_cost) AS (
SELECT
(
SELECT round(
current_setting('random_page_cost')::real * pages +
current_setting('cpu_index_tuple_cost')::real * tuples +
current_setting('cpu_operator_cost')::real * tuples
)
FROM (
SELECT relpages * 0.0630 AS pages,
reltuples * 0.0630 AS tuples
FROM pg_class WHERE relname = 'bookings_pkey'
) c
)AS idx_cost,

  
(
SELECT round(
(1 - frac_visible) *
-- fraction of non-all-visible pages
current_setting('seq_page_cost')::real * pages +
current_setting('cpu_tuple_cost')::real * tuples
)
FROM (
SELECT relpages * 0.0630 AS pages,
reltuples * 0.0630 AS tuples,
relallvisible::real/relpages::real AS frac_visible
FROM pg_class WHERE relname = 'bookings'
) c
)AS tbl_cost
)
SELECT idx_cost, tbl_cost, idx_cost + tbl_cost AS total
FROM costs;
idx_cost | tbl_cost | total
−−−−−−−−−−+−−−−−−−−−−+−−−−−−−
2457 | 1330 | 3787
(1 row)
            
             
           
  
            
=> CREATE TEMP TABLE bookings_tmp
WITH (autovacuum_enabled = off) AS
SELECT *FROM bookings
ORDER BY book_ref;
=> ALTER TABLE bookings_tmp ADD PRIMARY KEY(book_ref);
=> ANALYZE bookings_tmp;
=> EXPLAIN (analyze, timing off, summary off)
SELECT book_ref FROM bookings_tmp WHERE book_ref < '100000';
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Index Only Scan using bookings_tmp_pkey on bookings_tmp
(cost=0.43..4638.91 rows=132999 width=7) (actual rows=132109 l...
Index Cond: (book_ref < '100000'::bpchar)
Heap Fetches: 132109
(4 rows)

   
             
        
=> VACUUM bookings_tmp;
=> EXPLAIN (analyze, timing off, summary off)
SELECT book_ref FROM bookings_tmp WHERE book_ref < '100000';
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Index Only Scan using bookings_tmp_pkey on bookings_tmp
(cost=0.43..3787.91 rows=132999 width=7) (actual rows=132109 l...
Index Cond: (book_ref < '100000'::bpchar)
Heap Fetches: 0
(4 rows)
    
             

         
    
             
     
              
               
            
    
           
      
=> CREATE UNIQUE INDEX ON bookings(book_ref) INCLUDE (book_date);
=> BEGIN;
=> ALTER TABLE bookings
DROP CONSTRAINT bookings_pkey CASCADE;

  
NOTICE: drop cascades to constraint tickets_book_ref_fkey on table
tickets
ALTER TABLE
=> ALTER TABLE bookings ADD CONSTRAINT bookings_pkey PRIMARY KEY
USING INDEX bookings_book_ref_book_date_idx;
-- a new index
NOTICE: ALTER TABLE / ADD CONSTRAINT USING INDEX will rename index
"bookings_book_ref_book_date_idx" to "bookings_pkey"
ALTER TABLE
=> ALTER TABLE tickets
ADD FOREIGN KEY (book_ref) REFERENCES bookings(book_ref);
=> COMMIT;
=> EXPLAIN SELECT book_ref, book_date
FROM bookings WHERE book_ref < '100000';
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Index Only Scan using bookings_pkey on bookings (cost=0.43..437...
Index Cond: (book_ref < '100000'::bpchar)
(2 rows)
               
               
               
               
    
  
             
            
           
             
            
                

  

   
             

=> CREATE INDEX ON bookings(total_amount);
=> EXPLAIN
SELECT *FROM bookings WHERE total_amount = 48500.00;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Bitmap Heap Scan on bookings (cost=54.63..7040.42 rows=2865 wid...
Recheck Cond: (total_amount = 48500.00)
−> Bitmap Index Scan on bookings_total_amount_idx
(cost=0.00..53.92 rows=2865 width=0)
Index Cond: (total_amount = 48500.00)
(5 rows)
            
          
              
             
           
     
          
           
               
 
             
         
              
    1  
             
           
         
      

  



  
        
         
      
      10
 
              
                 
   4MB        
           
           
           
          
=> EXPLAIN (analyze, costs off, timing off, summary off)
SELECT *FROM bookings WHERE total_amount > 150000.00;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Bitmap Heap Scan on bookings (actual rows=242691 loops=1)
Recheck Cond: (total_amount > 150000.00)
Heap Blocks: exact=13447
−> Bitmap Index Scan on bookings_total_amount_idx (actual rows...
Index Cond: (total_amount > 150000.00)
(5 rows)
        
            
=> SET work_mem = '512kB';
  
  
  

   
=> EXPLAIN (analyze, costs off, timing off, summary off)
SELECT *FROM bookings WHERE total_amount > 150000.00;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Bitmap Heap Scan on bookings (actual rows=242691 loops=1)
Recheck Cond: (total_amount > 150000.00)
Rows Removed by Index Recheck: 1145721
Heap Blocks: exact=5178 lossy=8269
−> Bitmap Index Scan on bookings_total_amount_idx (actual rows...
Index Cond: (total_amount > 150000.00)
(6 rows)
=> RESET work_mem;
          
               
              
           
      
                 
                 
            
   
  
            
           
             
             
          
=> EXPLAIN (costs off)
SELECT *FROM bookings
WHERE book_date < '2016-08-28'
AND total_amount > 250000;


  
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Bitmap Heap Scan on bookings
Recheck Cond: ((total_amount > '250000'::numeric) AND (book_da...
−> BitmapAnd
−> Bitmap Index Scan on bookings_total_amount_idx
Index Cond: (total_amount > '250000'::numeric)
−> Bitmap Index Scan on bookings_book_date_idx
Index Cond: (book_date < '2016−08−28 00:00:00+03'::tim...
(7 rows)
           
           
             
           
 
         
=> EXPLAIN
SELECT *FROM bookings WHERE total_amount = 28000.00;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Bitmap Heap Scan on bookings (cost=599.48..14444.96 rows=31878 ...
Recheck Cond: (total_amount = 28000.00)
−> Bitmap Index Scan on bookings_total_amount_idx
(cost=0.00..591.51 rows=31878 width=0)
Index Cond: (total_amount = 28000.00)
(5 rows)
          
=> SELECT round(31878::numeric/reltuples::numeric, 4)
FROM pg_class WHERE relname = 'bookings';
round
−−−−−−−−
0.0151
(1 row)
   

   
                
            
=> SELECT round(
current_setting('random_page_cost')::real * pages +
current_setting('cpu_index_tuple_cost')::real * tuples +
current_setting('cpu_operator_cost')::real * tuples
)
FROM (
SELECT relpages * 0.0151 AS pages, reltuples * 0.0151 AS tuples
FROM pg_class WHERE relname = 'bookings_total_amount_idx'
) c;
round
−−−−−−−
589
(1 row)
             
         
             
              
           
        
            
   
  
           
             
     
  

  
=> WITH tAS (
SELECT relpages,
least(
(2 * relpages * reltuples * 0.0151) /
(2 * relpages + reltuples * 0.0151),
relpages
)AS pages_fetched,
round(reltuples * 0.0151) AS tuples_fetched,
current_setting('random_page_cost')::real AS rnd_cost,
current_setting('seq_page_cost')::real AS seq_cost
FROM pg_class WHERE relname = 'bookings'
)
SELECT pages_fetched,
rnd_cost - (rnd_cost - seq_cost) *
sqrt(pages_fetched / relpages) AS cost_per_page,
tuples_fetched
FROM t;
pages_fetched | cost_per_page | tuples_fetched
−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−
13447 | 1 | 31878
(1 row)
            
               
             
            
    
a lossy bitmap segment an exact segment
            
              
    
  

   
           
  
               
             
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Bitmap Heap Scan on bookings
(cost=599.48..14444.96 rows=31878 width=21)
Recheck Cond: (total_amount = 28000.00)
−> Bitmap Index Scan on bookings_total_amount_idx
(cost=0.00..591.51 rows=31878 width=0)
Index Cond: (total_amount = 28000.00)
(6 rows)
            
=> WITH tAS (
SELECT 1AS cost_per_page,
13447 AS pages_fetched,
31878 AS tuples_fetched
),
costs(startup_cost, run_cost) AS (
SELECT
(SELECT round(
589
/* cost estimation for the child node */
+
0.1 * current_setting('cpu_operator_cost')::real *
reltuples * 0.0151
)
FROM pg_class WHERE relname = 'bookings_total_amount_idx'
),
(SELECT round(
cost_per_page * pages_fetched +
current_setting('cpu_tuple_cost')::real * tuples_fetched +
current_setting('cpu_operator_cost')::real * tuples_fetched
)
FROM t
)
)
SELECT startup_cost, run_cost,
startup_cost + run_cost AS total_cost
FROM costs;
  

   
startup_cost | run_cost | total_cost
−−−−−−−−−−−−−−+−−−−−−−−−−+−−−−−−−−−−−−
597 | 13845 | 14442
(1 row)
              
         
   
            
        
              
              
           
           
   
            
  
  
=> EXPLAIN SELECT sum(total_amount)
FROM bookings WHERE book_ref < '400000';
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Finalize Aggregate (cost=19192.81..19192.82 rows=1 width=32)
−> Gather (cost=19192.59..19192.80 rows=2 width=32)
Workers Planned: 2
−> Partial Aggregate (cost=18192.59..18192.60 rows=1 widt...
−> Parallel Index Scan using bookings_pkey on bookings
(cost=0.43..17642.82 rows=219907 width=6)
Index Cond: (book_ref < '400000'::bpchar)
(7 rows)
   

   
              
              
                
            
            
          
           
  
=> EXPLAIN SELECT sum(total_amount)
FROM bookings WHERE total_amount < 50000.00;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Finalize Aggregate (cost=23370.60..23370.61 rows=1 width=32)
−> Gather (cost=23370.38..23370.59 rows=2 width=32)
Workers Planned: 2
−> Partial Aggregate (cost=22370.38..22370.39 rows=1 widt...
−> Parallel Index Only Scan using bookings_total_amoun...
(cost=0.43..21387.27 rows=393244 width=6)
Index Cond: (total_amount < 50000.00)
(7 rows)
            
      
  
=> EXPLAIN SELECT sum(total_amount)
FROM bookings WHERE book_date < '2016-10-01';
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Finalize Aggregate (cost=21492.21..21492.22 rows=1 width=32)
−> Gather (cost=21491.99..21492.20 rows=2 width=32)
Workers Planned: 2
−> Partial Aggregate (cost=20491.99..20492.00 rows=1 widt...
−> Parallel Bitmap Heap Scan on bookings
(cost=4891.17..20133.01 rows=143588 width=6)
Recheck Cond: (book_date < '2016−10−01 00:00:00+03...
−> Bitmap Index Scan on bookings_book_date_idx
(cost=0.00..4805.01 rows=344611 width=0)
Index Cond: (book_date < '2016−10−01 00:00:00+...
(10 rows)

     
           
              
             
          
 
     
           
   
selectivity
cost
0 1
index-only scan
bitmap index scan
index scan
seq scan
             
    
          
           
              
               
              

   
             
           
             
      
          
             
            
     
              
             
         
             
           
            
            


21
Nested Loop
    
              
            
          
     
             
             
             
         
              
          
            
             
              
                
           
 
              
 
            
            

   
            
                
        
              
            
         
             
              
              
 
    
  
 
 
           
           
            
              
              
             

             
      
   
             
                

   
                
            
     
               
           
      
            
  
         
 
            
       
=> EXPLAIN SELECT *FROM aircrafts_data a1
CROSS JOIN aircrafts_data a2
WHERE a2.range > 5000;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Nested Loop (cost=0.00..2.78 rows=45 width=144)
−> Seq Scan on aircrafts_data a1
(cost=0.00..1.09 rows=9 width=72)
−> Materialize (cost=0.00..1.14 rows=5 width=72)
−> Seq Scan on aircrafts_data a2
(cost=0.00..1.11 rows=5 width=72)
Filter: (range > 5000)
(7 rows)
inner set
outer set
            
              
             


   
             
              
         4MB  
           
             
              
 
           
=> EXPLAIN SELECT *
FROM tickets t
JOIN ticket_flights tf ON tf.ticket_no = t.ticket_no
WHERE t.ticket_no = '0005432000284';
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Nested Loop (cost=0.99..25.05 rows=3 width=136)
−> Index Scan using tickets_pkey on tickets t
(cost=0.43..8.45 rows=1 width=104)
Index Cond: (ticket_no = '0005432000284'::bpchar)
−> Index Scan using ticket_flights_pkey on ticket_flights tf
(cost=0.56..16.58 rows=3 width=32)
Index Cond: (ticket_no = '0005432000284'::bpchar)
(7 rows)
            
        
     
          
        
            
   



   
         
          
               
      
        
       
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Nested Loop (cost=0.99..25.05 rows=3 width=136)
−> Index Scan using tickets_pkey on tickets t
(cost=0.43..8.45 rows=1 width=104)
Index Cond: (ticket_no = '0005432000284'::bpchar)
−> Index Scan using ticket_flights_pkey on ticket_flights tf
(cost=0.56..16.58 rows=3 width=32)
Index Cond: (ticket_no = '0005432000284'::bpchar)
(7 rows)
1
        
=> SELECT 0.43 + 0.56 AS startup_cost,
round((
8.45 + 16.57 +
3 * current_setting('cpu_tuple_cost')::real
)::numeric, 2) AS total_cost;
startup_cost | total_cost
−−−−−−−−−−−−−−+−−−−−−−−−−−−
0.99 | 25.05
(1 row)
       
=> EXPLAIN SELECT *
FROM aircrafts_data a1
CROSS JOIN aircrafts_data a2
WHERE a2.range > 5000;

   
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Nested Loop (cost=0.00..2.78 rows=45 width=144)
−> Seq Scan on aircrafts_data a1
(cost=0.00..1.09 rows=9 width=72)
−> Materialize (cost=0.00..1.14 rows=5 width=72)
−> Seq Scan on aircrafts_data a2
(cost=0.00..1.11 rows=5 width=72)
Filter: (range > 5000)
(7 rows)
           
             
 
          
          
                
  
              
     
        
      
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Nested Loop (cost=0.00..2.78 rows=45 width=144)
−> Seq Scan on aircrafts_data a1
(cost=0.00..1.09 rows=9 width=72)
−> Materialize
(cost=0.00..1.14 rows=5 width=72)
−> Seq Scan on aircrafts_data a2
(cost=0.00..1.11 rows=5 width=72)
Filter: (range > 5000)
(8 rows)
9
   

   
            
               
            
  
             
=> SELECT 0.00 + 0.00 AS startup_cost,
round((
1.09 + (1.14 + 8 * 0.0125) +
45 * current_setting('cpu_tuple_cost')::real
)::numeric, 2) AS total_cost;
startup_cost | total_cost
−−−−−−−−−−−−−−+−−−−−−−−−−−−
0.00 | 2.78
(1 row)
 
            

=> CREATE INDEX ON tickets(book_ref);
=> EXPLAIN SELECT *
FROM tickets t
JOIN ticket_flights tf ON tf.ticket_no = t.ticket_no
WHERE t.book_ref = '03A76D';
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Nested Loop (cost=0.99..45.68 rows=6 width=136)
−> Index Scan using tickets_book_ref_idx on tickets t
(cost=0.43..12.46 rows=2 width=104)
Index Cond: (book_ref = '03A76D'::bpchar)
−> Index Scan using ticket_flights_pkey on ticket_flights tf
(cost=0.56..16.58 rows=3 width=32)
Index Cond: (ticket_no = t.ticket_no)
(7 rows)
  

   
               
              
            
             
         
               
          
             
                
              
 
           
          
              
              
             
           
                
                
    
             
   
=> SELECT round(2 * tf.reltuples * (1.0 / t.reltuples)) AS rows
FROM pg_class t, pg_class tf
WHERE t.relname = 'tickets'
AND tf.relname = 'ticket_flights';
rows
−−−−−−
6
(1 row)
  
  

   
            
           
           
         

 
               
  
             
               
        
=> SELECT t.n_distinct, tf.n_distinct
FROM pg_stats t, pg_stats tf
WHERE t.tablename = 'tickets' AND t.attname = 'ticket_no'
AND tf.tablename = 'ticket_flights' AND tf.attname = 'ticket_no';
n_distinct | n_distinct
−−−−−−−−−−−−+−−−−−−−−−−−−−
−1 | −0.30362356
(1 row)
            
=> SELECT round(2 * tf.reltuples *
least(1.0/t.reltuples, 1.0/tf.reltuples/0.30362356)
)AS rows
FROM pg_class t, pg_class tf
WHERE t.relname = 'tickets' AND tf.relname = 'ticket_flights';
rows
−−−−−−
6
(1 row)
           
               
             
             
            
  
  
  

   
              
              
    
             
            
=> EXPLAIN (analyze, timing off, summary off) SELECT *
FROM tickets t
JOIN ticket_flights tf ON tf.ticket_no = t.ticket_no
WHERE t.book_ref = '03A76D';
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Nested Loop (cost=0.99..45.68 rows=6 width=136)
(actual rows=8 loops=1)
−> Index Scan using tickets_book_ref_idx on tickets t
(cost=0.43..12.46 rows=2 width=104) (actual rows=2 loops=1)
Index Cond: (book_ref = '03A76D'::bpchar)
−> Index Scan using ticket_flights_pkey on ticket_flights tf
(cost=0.56..16.58 rows=3 width=32) (actual rows=4 loops=2)
Index Cond: (ticket_no = t.ticket_no)
(8 rows)
            
              
            

                  
              
             
               
         
             

    

   
=> EXPLAIN SELECT *
FROM tickets t
JOIN ticket_flights tf ON tf.ticket_no = t.ticket_no
WHERE t.book_ref = '03A76D';
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Nested Loop (cost=0.99..45.68 rows=6 width=136)
−> Index Scan using tickets_book_ref_idx on tickets t
(cost=0.43..12.46 rows=2 width=104)
Index Cond: (book_ref = '03A76D'::bpchar)
−> Index Scan using ticket_flights_pkey on ticket_flights tf
(cost=0.56..16.58 rows=3 width=32)
Index Cond: (ticket_no = t.ticket_no)
(7 rows)
                 
          
=> SELECT 0.43 + 0.56 AS startup_cost,
round((
12.46 + 2 * 16.57 +
6 * current_setting('cpu_tuple_cost')::real
)::numeric, 2) AS total_cost;
startup_cost | total_cost
−−−−−−−−−−−−−−+−−−−−−−−−−−−
0.99 | 45.66
(1 row)
   
             
                
          
            



   
          
          
   
             
            
  
        
=> EXPLAIN SELECT *
FROM flights f
JOIN aircrafts_data a ON f.aircraft_code = a.aircraft_code
WHERE f.flight_no = 'PG0003';
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Nested Loop (cost=5.44..387.10 rows=113 width=135)
−> Bitmap Heap Scan on flights f
(cost=5.30..382.22 rows=113 width=63)
Recheck Cond: (flight_no = 'PG0003'::bpchar)
−> Bitmap Index Scan on flights_flight_no_scheduled_depart...
(cost=0.00..5.27 rows=113 width=0)
Index Cond: (flight_no = 'PG0003'::bpchar)
−> Memoize (cost=0.15..0.27 rows=1 width=72)
Cache Key: f.aircraft_code
Cache Mode: logical
−> Index Scan using aircrafts_pkey on aircrafts_data a
(cost=0.14..0.26 rows=1 width=72)
Index Cond: (aircraft_code = f.aircraft_code)
(13 rows)
           4MB 
1.0          
            
                

                
               
    


   
            
               
               
   
              
              
     
               
            
             
             
               
             
                
           
               
                 
       0.01 
           
           
                
            
               
            
               
               
            
          
  
  
  

   
            
    
=> EXPLAIN (analyze, costs off, timing off, summary off)
SELECT *FROM flights f
JOIN aircrafts_data a ON f.aircraft_code = a.aircraft_code
WHERE f.flight_no = 'PG0003';
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Nested Loop (actual rows=113 loops=1)
−> Bitmap Heap Scan on flights f
(actual rows=113 loops=1)
Recheck Cond: (flight_no = 'PG0003'::bpchar)
Heap Blocks: exact=2
−> Bitmap Index Scan on flights_flight_no_scheduled_depart...
(actual rows=113 loops=1)
Index Cond: (flight_no = 'PG0003'::bpchar)
−> Memoize (actual rows=1 loops=113)
Cache Key: f.aircraft_code
Cache Mode: logical
Hits: 112 Misses: 1 Evictions: 0 Overflows: 0 Memory
Usage: 1kB
−> Index Scan using aircrafts_pkey on aircrafts_data a
(actual rows=1 loops=1)
Index Cond: (aircraft_code = f.aircraft_code)
(16 rows)
              
               
                
              
 
            
              
           
           
             
               
     on  

   
 
            
=> EXPLAIN SELECT *
FROM ticket_flights tf
LEFT JOIN boarding_passes bp ON bp.ticket_no = tf.ticket_no
AND bp.flight_id = tf.flight_id
WHERE tf.ticket_no = '0005434026720';
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Nested Loop Left Join (cost=1.12..33.35 rows=3 width=57)
Join Filter: ((bp.ticket_no = tf.ticket_no) AND (bp.flight_id =
tf.flight_id))
−> Index Scan using ticket_flights_pkey on ticket_flights tf
(cost=0.56..16.58 rows=3 width=32)
Index Cond: (ticket_no = '0005434026720'::bpchar)
−> Materialize (cost=0.56..16.62 rows=3 width=25)
−> Index Scan using boarding_passes_pkey on boarding_passe...
(cost=0.56..16.61 rows=3 width=25)
Index Cond: (ticket_no = '0005434026720'::bpchar)
(10 rows)
              
          
                
         
               
            
               
           
          
              
             
      
  

   
=> SET enable_mergejoin = off;
=> EXPLAIN SELECT *
FROM ticket_flights tf
JOIN boarding_passes bp ON bp.ticket_no = tf.ticket_no
AND bp.flight_id = tf.flight_id
WHERE tf.ticket_no = '0005434026720';
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Nested Loop (cost=1.12..33.33 rows=3 width=57)
Join Filter: (tf.flight_id = bp.flight_id)
−> Index Scan using ticket_flights_pkey on ticket_flights tf
(cost=0.56..16.58 rows=3 width=32)
Index Cond: (ticket_no = '0005434026720'::bpchar)
−> Materialize (cost=0.56..16.62 rows=3 width=25)
−> Index Scan using boarding_passes_pkey on boarding_passe...
(cost=0.56..16.61 rows=3 width=25)
Index Cond: (ticket_no = '0005434026720'::bpchar)
(9 rows)
=> RESET enable_mergejoin;
              
                
  
            
                
              
    
        
  
              
               
                 
                
  

   
              
 
         
          
        
=> EXPLAIN SELECT *
FROM aircrafts a
WHERE NOT EXISTS (
SELECT *FROM seats s WHERE s.aircraft_code = a.aircraft_code
);
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Nested Loop Anti Join (cost=0.28..4.65 rows=1 width=40)
−> Seq Scan on aircrafts_data ml (cost=0.00..1.09 rows=9 widt...
−> Index Only Scan using seats_pkey on seats s
(cost=0.28..5.55 rows=149 width=4)
Index Cond: (aircraft_code = ml.aircraft_code)
(5 rows)
            
=> EXPLAIN SELECT a.*
FROM aircrafts a
LEFT JOIN seats s ON a.aircraft_code = s.aircraft_code
WHERE s.aircraft_code IS NULL;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Nested Loop Anti Join (cost=0.28..4.65 rows=1 width=40)
−> Seq Scan on aircrafts_data ml (cost=0.00..1.09 rows=9 widt...
−> Index Only Scan using seats_pkey on seats s
(cost=0.28..5.55 rows=149 width=4)
Index Cond: (aircraft_code = ml.aircraft_code)
(5 rows)
               
              
  
            
      

   
=> EXPLAIN SELECT *
FROM aircrafts a
WHERE EXISTS (
SELECT *FROM seats s
WHERE s.aircraft_code = a.aircraft_code
);
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Nested Loop Semi Join (cost=0.28..6.67 rows=9 width=40)
−> Seq Scan on aircrafts_data ml (cost=0.00..1.09 rows=9 widt...
−> Index Only Scan using seats_pkey on seats s
(cost=0.28..5.55 rows=149 width=4)
Index Cond: (aircraft_code = ml.aircraft_code)
(5 rows)
            
            
               
            
=> EXPLAIN (analyze, costs off, timing off, summary off)
SELECT *FROM aircrafts a
WHERE EXISTS (
SELECT *FROM seats s
WHERE s.aircraft_code = a.aircraft_code
);
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Nested Loop Semi Join (actual rows=9 loops=1)
−> Seq Scan on aircrafts_data ml (actual rows=9 loops=1)
−> Index Only Scan using seats_pkey on seats s
(actual rows=1 loops=9)
Index Cond: (aircraft_code = ml.aircraft_code)
Heap Fetches: 0
(6 rows)
          
              
          
  

   
            
               

             
                
               
                
          
             
         
=> CREATE EXTENSION earthdistance CASCADE;
=> EXPLAIN (costs off) SELECT *
FROM airports a1
JOIN airports a2 ON a1.airport_code != a2.airport_code
AND a1.coordinates <@> a2.coordinates < 100;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Nested Loop
Join Filter: ((ml.airport_code <> ml_1.airport_code) AND
((ml.coordinates <@> ml_1.coordinates) < '100'::double precisi...
−> Seq Scan on airports_data ml
−> Materialize
−> Seq Scan on airports_data ml_1
(6 rows)
  
         
                 
          
              
  
  

   
            
   
=> EXPLAIN (costs off) SELECT t.passenger_name
FROM tickets t
JOIN ticket_flights tf ON tf.ticket_no = t.ticket_no
JOIN flights f ON f.flight_id = tf.flight_id
WHERE f.flight_id = 12345;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Nested Loop
−> Index Only Scan using flights_flight_id_status_idx on fligh...
Index Cond: (flight_id = 12345)
−> Gather
Workers Planned: 2
−> Nested Loop
−> Parallel Seq Scan on ticket_flights tf
Filter: (flight_id = 12345)
−> Index Scan using tickets_pkey on tickets t
Index Cond: (ticket_no = tf.ticket_no)
(10 rows)
            
              
          
               
              
 

22
Hashing
  
  
            
     
=> EXPLAIN (costs off) SELECT *
FROM tickets t
JOIN ticket_flights tf ON tf.ticket_no = t.ticket_no;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Hash Join
Hash Cond: (tf.ticket_no = t.ticket_no)
−> Seq Scan on ticket_flights tf
−> Hash
−> Seq Scan on tickets t
(5 rows)
 rst stage          
             
              
                 
           
               
                
       



  
           
     
 rst stage            
             
               
    
               
               
           4MB 
1.0  
outer
set
inner
set
work_mem
hash_mem_multiplier
             
=> SET work_mem = '256MB';
=> EXPLAIN (analyze, costs off, timing off, summary off)
SELECT *FROM bookings b
JOIN tickets t ON b.book_ref = t.book_ref;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Hash Join (actual rows=2949857 loops=1)
Hash Cond: (t.book_ref = b.book_ref)
−> Seq Scan on tickets t (actual rows=2949857 loops=1)
−> Hash (actual rows=2111110 loops=1)
Buckets: 4194304 Batches: 1 Memory Usage: 145986kB
−> Seq Scan on bookings b (actual rows=2111110 loops=1)
(6 rows)


  
            
                
   
               
            
 
               
=> EXPLAIN (analyze, costs off, timing off, summary off)
SELECT b.book_ref
FROM bookings b
JOIN tickets t ON b.book_ref = t.book_ref;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Hash Join (actual rows=2949857 loops=1)
Hash Cond: (t.book_ref = b.book_ref)
−> Index Only Scan using tickets_book_ref_idx on tickets t
(actual rows=2949857 loops=1)
Heap Fetches: 0
−> Hash (actual rows=2111110 loops=1)
Buckets: 4194304 Batches: 1 Memory Usage: 113172kB
−> Seq Scan on bookings b (actual rows=2111110 loops=1)
(8 rows)
=> RESET work_mem;
             
           
            
             
            
            
          
             
        
            
  

  
 second stage            
                
              
            
outer
set
        
           
          
                
            
         
   
=> EXPLAIN (analyze, timing off, summary off)
SELECT *FROM flights f
JOIN seats s ON s.aircraft_code = f.aircraft_code;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Hash Join (cost=38.13..278507.28 rows=16518865 width=78)
(actual rows=16518865 loops=1)
Hash Cond: (f.aircraft_code = s.aircraft_code)
−> Seq Scan on flights f (cost=0.00..4772.67 rows=214867 widt...
(actual rows=214867 loops=1)
−> Hash (cost=21.39..21.39 rows=1339 width=15)
(actual rows=1339 loops=1)
Buckets: 2048 Batches: 1 Memory Usage: 79kB
−> Seq Scan on seats s (cost=0.00..21.39 rows=1339 width=15)
(actual rows=1339 loops=1)
(10 rows)
  
    

  
              
   
               
             
           0.0025  

              
0.01   
               
 
              
             
         
            
       
       
             
              
             
            
          
         
=> WITH cost(startup) AS (
SELECT round((
21.39 +
current_setting('cpu_operator_cost')::real * 1339 +
current_setting('cpu_tuple_cost')::real * 1339 +
0.00
)::numeric, 2)
)
  

  
SELECT startup,
startup + round((
4772.67 +
current_setting('cpu_operator_cost')::real * 214867 +
current_setting('cpu_operator_cost')::real * 214867 * 1339 *
0.150112 +
current_setting('cpu_tuple_cost')::real * 16518865
)::numeric, 2) AS total
FROM cost;
startup | total
−−−−−−−−−+−−−−−−−−−−−
38.13 | 278507.26
(1 row)
     
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Hash Join
(cost=38.13..278507.28 rows=16518865 width=78)
Hash Cond: (f.aircraft_code = s.aircraft_code)
−> Seq Scan on flights f
(cost=0.00..4772.67 rows=214867 width=63)
−> Hash
(cost=21.39..21.39 rows=1339 width=15)
−> Seq Scan on seats s
(cost=0.00..21.39 rows=1339 width=15)
(9 rows)
  
              
               
               
             
              
       
  

  
              
             
      
 rst stage             
                 
              

              
−1            
        
outer
set
inner
set
 second stage             
               
          
               
           
         
              
             
  
  

  
outer
set
inner
set
               
              
               
          
outer
set
            
             
      
=> EXPLAIN (analyze, buffers, costs off, timing off, summary off)
SELECT *
FROM bookings b
JOIN tickets t ON b.book_ref = t.book_ref;

  
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Hash Join (actual rows=2949857 loops=1)
Hash Cond: (t.book_ref = b.book_ref)
Buffers: shared hit=7236 read=55626, temp read=55126
written=55126
−> Seq Scan on tickets t (actual rows=2949857 loops=1)
Buffers: shared read=49415
−> Hash (actual rows=2111110 loops=1)
Buckets: 65536 Batches: 64 Memory Usage: 2277kB
Buffers: shared hit=7236 read=6211, temp written=10858
−> Seq Scan on bookings b (actual rows=2111110 loops=1)
Buffers: shared hit=7236 read=6211
(11 rows)
           
                 
               
               
              
     
          −1 
                
      
 
            
   
            
    
                 
                 
               
               

  
             
            
            

               
            
     
                
               
              
        
            
             
         
              
         
            
                
              
            
        
             
        
            
   
=> CREATE TABLE bookings_copy (LIKE bookings INCLUDING INDEXES)
WITH (autovacuum_enabled = off);
=> INSERT INTO bookings_copy SELECT *FROM bookings;
INSERT 0 2111110
  
  

  
=> DELETE FROM bookings_copy WHERE random() < 0.9;
DELETE 1899232
=> ANALYZE bookings_copy;
=> INSERT INTO bookings_copy SELECT *FROM bookings
ON CONFLICT DO NOTHING;
INSERT 0 1899232
=> SELECT reltuples FROM pg_class WHERE relname = 'bookings_copy';
reltuples
−−−−−−−−−−−
211878
(1 row)
              
            
              
          
           
         
=> EXPLAIN (analyze, costs off, timing off, summary off)
SELECT *
FROM bookings_copy b
JOIN tickets t ON b.book_ref = t.book_ref;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Hash Join (actual rows=2949857 loops=1)
Hash Cond: (t.book_ref = b.book_ref)
−> Seq Scan on tickets t (actual rows=2949857 loops=1)
−> Hash (actual rows=2111110 loops=1)
Buckets: 65536 (originally 65536) Batches: 32 (originally 8)
Memory Usage: 4040kB
−> Seq Scan on bookings_copy b (actual rows=2111110 loops=1)
(7 rows)
          
              
               
 

  
=> SET work_mem = '64kB';
=> EXPLAIN (analyze, timing off, summary off)
SELECT *FROM flights f
JOIN seats s ON s.aircraft_code = f.aircraft_code;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Hash Join (cost=45.13..283139.28 rows=16518865 width=78)
(actual rows=16518865 loops=1)
Hash Cond: (f.aircraft_code = s.aircraft_code)
−> Seq Scan on flights f (cost=0.00..4772.67 rows=214867 widt...
(actual rows=214867 loops=1)
−> Hash (cost=21.39..21.39 rows=1339 width=15)
(actual rows=1339 loops=1)
Buckets: 2048 Batches: 2 Memory Usage: 55kB
−> Seq Scan on seats s (cost=0.00..21.39 rows=1339 width=15)
(actual rows=1339 loops=1)
(10 rows)
=> RESET work_mem;
              
    
              
              
               
               
           
               
               
         
            
    
               
                
             
    
  

  
=> SELECT 38.13 +
-- startup cost of a one-pass join
current_setting('seq_page_cost')::real * 7
AS startup,
278507.28 +
-- total cost of a one-pass join
current_setting('seq_page_cost')::real * 2 * (7 + 2309)
AS total;
startup | total
−−−−−−−−−+−−−−−−−−−−−
45.13 | 283139.28
(1 row)
               
           
            
 
             
  
      
             
           
            
            
    
       
=> SET work_mem = '128MB';
=> SET enable_parallel_hash = off;
=> EXPLAIN (analyze, costs off, timing off, summary off)
SELECT count(*)
FROM bookings b
JOIN tickets t ON t.book_ref = b.book_ref;

  
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Finalize Aggregate (actual rows=1 loops=1)
−> Gather (actual rows=3 loops=1)
Workers Planned: 2
Workers Launched: 2
−> Partial Aggregate (actual rows=1 loops=3)
−> Hash Join (actual rows=983286 loops=3)
Hash Cond: (t.book_ref = b.book_ref)
−> Parallel Index Only Scan using tickets_book_ref...
Heap Fetches: 0
−> Hash (actual rows=2111110 loops=3)
Buckets: 4194304 Batches: 1 Memory Usage:
113172kB
−> Seq Scan on bookings b (actual rows=2111110...
(13 rows)
=> RESET enable_parallel_hash;
             
             
  
             
              
     
    
            
            
           
             
             
            
            
           
       

  
 rst stage            
            
 
outer
set
inner
set
work_mem
hash_mem_multiplier
number of processes
            

 second stage           
               
     
outer
set
      
=> SET work_mem = '64MB';
=> EXPLAIN (analyze, costs off, timing off, summary off)
SELECT count(*)
FROM bookings b
JOIN tickets t ON t.book_ref = b.book_ref;
  

  

  
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Finalize Aggregate (actual rows=1 loops=1)
−> Gather (actual rows=3 loops=1)
Workers Planned: 2
Workers Launched: 2
−> Partial Aggregate (actual rows=1 loops=3)
−> Parallel Hash Join (actual rows=983286 loops=3)
Hash Cond: (t.book_ref = b.book_ref)
−> Parallel Index Only Scan using tickets_book_ref...
Heap Fetches: 0
−> Parallel Hash (actual rows=703703 loops=3)
Buckets: 4194304 Batches: 1 Memory Usage:
115392kB
−> Parallel Seq Scan on bookings b (actual row...
(13 rows)
=> RESET work_mem;
               
    on     
             
            
           
                
 
    
             
            
            
         
             
             
            
              

  
              
              
  
   rst stage          
           
                
                
            
           
            
outer
set
inner
set
            second stage

             
              
              
           
             
          
  
  
  

  
  

  
                
    
              
             
outer
set
inner
set
              
                
             
         
outer
set
inner
set
             
            
           
     
  

  
outer
set
              
            

              
               
            
            
          
=> EXPLAIN (costs off) SELECT *
FROM bookings b
LEFT OUTER JOIN tickets t ON t.book_ref = b.book_ref;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Hash Right Join
Hash Cond: (t.book_ref = b.book_ref)
−> Seq Scan on tickets t
−> Hash
−> Seq Scan on bookings b
(5 rows)
             
         
              
            
        

  
              
               
               
                 
 
               
            
=> EXPLAIN (costs off) SELECT *
FROM bookings b
RIGHT OUTER JOIN tickets t ON t.book_ref = b.book_ref;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Hash Left Join
Hash Cond: (t.book_ref = b.book_ref)
−> Seq Scan on tickets t
−> Hash
−> Seq Scan on bookings b
(5 rows)
            
 
=> EXPLAIN (costs off) SELECT *
FROM bookings b
FULL OUTER JOIN tickets t ON t.book_ref = b.book_ref;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Hash Full Join
Hash Cond: (t.book_ref = b.book_ref)
−> Seq Scan on tickets t
−> Hash
−> Seq Scan on bookings b
(5 rows)
           
               
         


    
=> EXPLAIN (costs off) SELECT sum(b.total_amount)
FROM bookings b
LEFT OUTER JOIN tickets t ON t.book_ref = b.book_ref;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Finalize Aggregate
−> Gather
Workers Planned: 2
−> Partial Aggregate
−> Parallel Hash Left Join
Hash Cond: (b.book_ref = t.book_ref)
−> Parallel Seq Scan on bookings b
−> Parallel Hash
−> Parallel Index Only Scan using tickets_book...
(9 rows)
    
           
             
             
              
 
        
        
         
=> EXPLAIN (costs off) SELECT fare_conditions, count(*)
FROM seats
GROUP BY fare_conditions;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
HashAggregate
Group Key: fare_conditions
−> Seq Scan on seats
(3 rows)


  
     
=> EXPLAIN (costs off) SELECT DISTINCT fare_conditions
FROM seats;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
HashAggregate
Group Key: fare_conditions
−> Seq Scan on seats
(3 rows)
       
=> EXPLAIN (costs off) SELECT fare_conditions
FROM seats
UNION
SELECT NULL;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
HashAggregate
Group Key: seats.fare_conditions
−> Append
−> Seq Scan on seats
−> Result
(5 rows)
              
             
 
           4MB 
1.0          
           
=> EXPLAIN (analyze, costs off, timing off, summary off)
SELECT DISTINCT amount FROM ticket_flights;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
HashAggregate (actual rows=338 loops=1)
Group Key: amount
Batches: 1 Memory Usage: 61kB
−> Seq Scan on ticket_flights (actual rows=8391852 loops=1)
(4 rows)

    
               
    
               
            
               
              
             
            
       
             
        
              
                
             
          
            
          
              
      
=> EXPLAIN (analyze, costs off, timing off, summary off)
SELECT DISTINCT flight_id FROM ticket_flights;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
HashAggregate (actual rows=150588 loops=1)
Group Key: flight_id
Batches: 5 Memory Usage: 4145kB Disk Usage: 98184kB
−> Seq Scan on ticket_flights (actual rows=8391852 loops=1)
(4 rows)
               
              
           
  

23
Sorting and Merging
  
             
             
           
  
              
     
=> EXPLAIN (costs off) SELECT *
FROM tickets t
JOIN ticket_flights tf ON tf.ticket_no = t.ticket_no
ORDER BY t.ticket_no;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Merge Join
Merge Cond: (t.ticket_no = tf.ticket_no)
−> Index Scan using tickets_pkey on tickets t
−> Index Scan using ticket_flights_pkey on ticket_flights tf
(4 rows)
            
             
               
  


  
             
           
=> EXPLAIN (costs off) SELECT *
FROM tickets t
JOIN ticket_flights tf ON t.ticket_no = tf.ticket_no
JOIN boarding_passes bp ON bp.ticket_no = tf.ticket_no
AND bp.flight_id = tf.flight_id
ORDER BY t.ticket_no;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Merge Join
Merge Cond: (tf.ticket_no = t.ticket_no)
−> Merge Join
Merge Cond: ((tf.ticket_no = bp.ticket_no) AND (tf.flight_...
−> Index Scan using ticket_flights_pkey on ticket_flights tf
−> Index Scan using boarding_passes_pkey on boarding_passe...
−> Index Scan using tickets_pkey on tickets t
(7 rows)
            
            
              
     
               
             
      
               
                 
              
             
 
              
             
              
                
      
  

    
                
 
            
          
  
         
=> EXPLAIN SELECT *
FROM tickets t
JOIN ticket_flights tf ON tf.ticket_no = t.ticket_no
ORDER BY t.ticket_no;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Merge Join (cost=0.99..822355.54 rows=8391852 width=136)
Merge Cond: (t.ticket_no = tf.ticket_no)
−> Index Scan using tickets_pkey on tickets t
(cost=0.43..139110.29 rows=2949857 width=104)
−> Index Scan using ticket_flights_pkey on ticket_flights tf
(cost=0.56..570972.46 rows=8391852 width=32)
(6 rows)
                
                
              
               
          
               
 
                
             
               
                  
          
   
  

  
               
           
             
           
              
   0.0025       
                
            
      0.01   
            
=> SELECT 0.43 + 0.56 AS startup,
round((
139110.29 + 570972.46 +
current_setting('cpu_tuple_cost')::real * 8391852 +
current_setting('cpu_operator_cost')::real * (2949857 + 8391852)
)::numeric, 2) AS total;
startup | total
−−−−−−−−−+−−−−−−−−−−−
0.99 | 822355.54
(1 row)
  
               
               
      
               
=> SET enable_hashjoin = off;
          
  
   
  

    
=> EXPLAIN (costs off)
SELECT count(*), sum(tf.amount)
FROM tickets t
JOIN ticket_flights tf ON tf.ticket_no = t.ticket_no;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Finalize Aggregate
−> Gather
Workers Planned: 2
−> Partial Aggregate
−> Merge Join
Merge Cond: (tf.ticket_no = t.ticket_no)
−> Parallel Index Scan using ticket_flights_pkey o...
−> Index Only Scan using tickets_pkey on tickets t
(8 rows)
           

              
            
       
             
       
           
=> EXPLAIN (costs off) SELECT *
FROM tickets t
FULL JOIN ticket_flights tf ON tf.ticket_no = t.ticket_no
ORDER BY t.ticket_no;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Sort
Sort Key: t.ticket_no
−> Merge Full Join
Merge Cond: (t.ticket_no = tf.ticket_no)
−> Index Scan using tickets_pkey on tickets t
−> Index Scan using ticket_flights_pkey on ticket_flights tf
(6 rows)
  

 
              
             
             
            
              
       
             
             
            

=> EXPLAIN (costs off) SELECT *
FROM tickets t
FULL JOIN ticket_flights tf ON tf.ticket_no = t.ticket_no
AND tf.amount > 0
ORDER BY t.ticket_no;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Sort
Sort Key: t.ticket_no
−> Hash Full Join
Hash Cond: (tf.ticket_no = t.ticket_no)
Join Filter: (tf.amount > '0'::numeric)
−> Seq Scan on ticket_flights tf
−> Hash
−> Seq Scan on tickets t
(8 rows)
            
=> RESET enable_hashjoin;
 
                  
          
      
  


    
=> EXPLAIN (costs off)
SELECT *FROM flights f
JOIN airports_data dep ON f.departure_airport = dep.airport_code
ORDER BY dep.airport_code;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Merge Join
Merge Cond: (f.departure_airport = dep.airport_code)
−> Sort
Sort Key: f.departure_airport
−> Seq Scan on flights f
−> Sort
Sort Key: dep.airport_code
−> Seq Scan on airports_data dep
(8 rows)
               
         
=> EXPLAIN (costs off)
SELECT flight_id,
row_number() OVER (PARTITION BY flight_no ORDER BY flight_id)
FROM flights f;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
WindowAgg
−> Sort
Sort Key: flight_no, flight_id
−> Seq Scan on flights f
(4 rows)
           
     
             
              
    
=> EXPLAIN (analyze,costs off,timing off,summary off)
SELECT *FROM flights f
JOIN airports_data dep ON f.departure_airport = dep.airport_code
ORDER BY dep.airport_code;


 
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Merge Join (actual rows=214867 loops=1)
Merge Cond: (f.departure_airport = dep.airport_code)
−> Sort (actual rows=214867 loops=1)
Sort Key: f.departure_airport
Sort Method: external merge Disk: 17136kB
−> Seq Scan on flights f (actual rows=214867 loops=1)
−> Sort (actual rows=104 loops=1)
Sort Key: dep.airport_code
Sort Method: quicksort Memory: 52kB
−> Seq Scan on airports_data dep (actual rows=104 loops=1)
(10 rows)

         4MB      
             
 
        
           
    
              
        
=> EXPLAIN SELECT *
FROM airports_data
ORDER BY airport_code;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Sort (cost=7.52..7.78 rows=104 width=145)
Sort Key: airport_code
−> Seq Scan on airports_data (cost=0.00..4.04 rows=104 width=...
(3 rows)


    
          
       0.0025  
               
               
    
               
           
         
        
=> WITH costs(startup) AS (
SELECT 4.04 + round((
current_setting('cpu_operator_cost')::real * 2 *
104 * log(2, 104)
)::numeric, 2)
)
SELECT startup,
startup + round((
current_setting('cpu_operator_cost')::real * 104
)::numeric, 2) AS total
FROM costs;
startup | total
−−−−−−−−−+−−−−−−−
7.52 | 7.78
(1 row)
 
               
             
              
             
     
=> EXPLAIN (analyze, timing off, summary off)
SELECT *FROM seats
ORDER BY seat_no LIMIT 100;
  

 
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Limit (cost=72.57..72.82 rows=100 width=15)
(actual rows=100 loops=1)
−> Sort (cost=72.57..75.91 rows=1339 width=15)
(actual rows=100 loops=1)
Sort Key: seat_no
Sort Method: top−N heapsort Memory: 33kB
−> Seq Scan on seats (cost=0.00..21.39 rows=1339 width=15)
(actual rows=1339 loops=1)
(8 rows)
             
              
             
         
            
         
          
           
      
=> WITH costs(startup)
AS (
SELECT 21.39 + round((
current_setting('cpu_operator_cost')::real * 2 *
1339 * log(2, 2 * 100)
)::numeric, 2)
)
SELECT startup,
startup + round((
current_setting('cpu_operator_cost')::real * 100
)::numeric, 2) AS total
FROM costs;
startup | total
−−−−−−−−−+−−−−−−−
72.57 | 72.82
(1 row)
  

    
 
                 
             
             
    
1 2 3451
             
          
23451 2
            
               
      
              
                 
             
              
 

 
               
             
             
             
  
        
           
           
               
            
               
            
               
      
123451+2+3
451+2+3 4+5
  

            

    
       
1+2+3 4+5
              
  
              
          
             
              
   
=> EXPLAIN (analyze, buffers, costs off, timing off, summary off)
SELECT *FROM flights
ORDER BY scheduled_departure;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Sort (actual rows=214867 loops=1)
Sort Key: scheduled_departure
Sort Method: external merge Disk: 17136kB
Buffers: shared hit=2627, temp read=2142 written=2150
−> Seq Scan on flights (actual rows=214867 loops=1)
Buffers: shared hit=2624
(6 rows)
             
  
            
=> EXPLAIN SELECT *
FROM flights
ORDER BY scheduled_departure;

 
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Sort (cost=31883.96..32421.12 rows=214867 width=63)
Sort Key: scheduled_departure
−> Seq Scan on flights (cost=0.00..4772.67 rows=214867 width=63)
(3 rows)
               
             
               
             
  
             
     
               
             
                 
                 
      
      
          
=> WITH costs(startup) AS (
SELECT 4772.67 + round((
current_setting('cpu_operator_cost')::real * 2 *
214867 * log(2, 214867) +
(current_setting('seq_page_cost')::real * 0.75 +
current_setting('random_page_cost')::real * 0.25) *
2 * 2309 * 1
-- one iteration
)::numeric, 2)
)
SELECT startup,
startup + round((
current_setting('cpu_operator_cost')::real * 214867
)::numeric, 2) AS total
FROM costs;
  
  

    
startup | total
−−−−−−−−−−+−−−−−−−−−−
31883.96 | 32421.13
(1 row)
  
               
               
              
             
    +      

          
             
            
   
          
           
            
          
=> EXPLAIN (analyze, costs off, timing off, summary off)
SELECT *FROM bookings
ORDER BY total_amount, book_date;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Incremental Sort (actual rows=2111110 loops=1)
Sort Key: total_amount, book_date
Presorted Key: total_amount
Full−sort Groups: 2823 Sort Method: quicksort Average
Memory: 30kB Peak Memory: 30kB
Pre−sorted Groups: 2624 Sort Method: quicksort Average



 
Memory: 3152kB Peak Memory: 3259kB
−> Index Scan using bookings_total_amount_idx on bookings (ac...
(8 rows)
                
             
           
              
            
           
            
   
          
=> EXPLAIN (costs off)
SELECT row_number() OVER (ORDER BY total_amount, book_date)
FROM bookings;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
WindowAgg
−> Incremental Sort
Sort Key: total_amount, book_date
Presorted Key: total_amount
−> Index Scan using bookings_total_amount_idx on bookings
(5 rows)
          
           
    
             
              
 
         
  
  

    
  
           
             
          
         
=> EXPLAIN (analyze, costs off, timing off, summary off)
SELECT *
FROM flights
ORDER BY scheduled_departure
LIMIT 10;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Limit (actual rows=10 loops=1)
−> Gather Merge (actual rows=10 loops=1)
Workers Planned: 1
Workers Launched: 1
−> Sort (actual rows=7 loops=2)
Sort Key: scheduled_departure
Sort Method: top−N heapsort Memory: 27kB
Worker 0: Sort Method: top−N heapsort Memory: 27kB
−> Parallel Seq Scan on flights (actual rows=107434 lo...
(9 rows)
            
            
            
             
   
              
                 
      1000 



 
            
            
        0.0025
            
           
              
          0.1 
           
            
         
       
               
              
              
              
               
=> EXPLAIN SELECT amount, count(*)
FROM ticket_flights
GROUP BY amount;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Finalize GroupAggregate (cost=123399.62..123485.00 rows=337 wid...
Group Key: amount
−> Gather Merge (cost=123399.62..123478.26 rows=674 width=14)
Workers Planned: 2
−> Sort (cost=122399.59..122400.44 rows=337 width=14)
Sort Key: amount
−> Partial HashAggregate (cost=122382.07..122385.44 r...
Group Key: amount
−> Parallel Seq Scan on ticket_flights (cost=0.00...
(9 rows)
             
      
  

    
=> WITH costs(startup, run) AS (
SELECT round((
-- launching processes
current_setting('parallel_setup_cost')::real +
-- building the heap
current_setting('cpu_operator_cost')::real * 2 * 3 * log(2, 3)
)::numeric, 2),
round((
-- passing rows
current_setting('parallel_tuple_cost')::real * 1.05 * 674 +
-- updating the heap
current_setting('cpu_operator_cost')::real * 2 * 674 * log(2, 3) +
current_setting('cpu_operator_cost')::real * 674
)::numeric, 2)
)
SELECT 122399.59 + startup AS startup,
122400.44 + startup + run AS total
FROM costs;
startup | total
−−−−−−−−−−−+−−−−−−−−−−−
123399.61 | 123478.26
(1 row)
    
            
             
           
            
   
=> EXPLAIN (costs off) SELECT DISTINCT book_ref
FROM bookings
ORDER BY book_ref;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Result
−> Unique
−> Index Only Scan using bookings_pkey on bookings
(3 rows)


    
      
=> EXPLAIN (costs off) SELECT book_ref, count(*)
FROM bookings
GROUP BY book_ref
ORDER BY book_ref;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
GroupAggregate
Group Key: book_ref
−> Index Only Scan using bookings_pkey on bookings
(3 rows)
            
     
            
           
          
          
    
=> SET work_mem = '64kB';
=> EXPLAIN (costs off) SELECT count(*)
FROM flights
GROUP BY GROUPING SETS (aircraft_code, flight_no, departure_airport);
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
MixedAggregate
Hash Key: departure_airport
Group Key: aircraft_code
Sort Key: flight_no
Group Key: flight_no
−> Sort
Sort Key: aircraft_code
−> Seq Scan on flights
(8 rows)
=> RESET work_mem;
            
             
 
  

    
             
             
              
              
              
          
              
             
               
     
              
      
    
              
        
              
                 
               
            
         
              
         
              
               
             
               
              
            
            
 

    
           
            
             
               
            

               
             
            
     
            
              
   
            
               
             
                
              
          
             
              
          
             
                  
                
           
              
           
            
  
               
             
       

    
            
 
         
          
selectivity
cost
0 1
nested loop
merge join + sort
hash join
merge join + index
               
              
    
               
             
     
                
             
       
              
                

    
             
  
               


Part V
Types of Indexes
24
Hash
 
          
             
         
             
          
             
                
               
 
            
                
               
            
        
            
           
              



  
  


  
             

              
           
             
    
  
             
             
          
      
          
         
          
    
           
      
         
     
=> CREATE EXTENSION pageinspect;
=> CREATE TABLE t(n integer);
=> ANALYZE t;
=> CREATE INDEX ON tUSING hash(n);
              
            
      
  

  
            
      
=> SELECT page, hash_page_type(get_raw_page('t_n_idx', page))
FROM generate_series(0,3) page;
page | hash_page_type
−−−−−−+−−−−−−−−−−−−−−−−
0 | metapage
1 | bucket
2 | bucket
3 | bitmap
(4 rows)
bucket 0bucket 0 bucket 1bucket 1
meta-
page bitmap
           
       
=> SELECT ntuples, ffactor, maxbucket
FROM hash_metapage_info(get_raw_page('t_n_idx', 0));
ntuples | ffactor | maxbucket
−−−−−−−−−+−−−−−−−−−+−−−−−−−−−−−
0 | 307 | 1
(1 row)
              
         75    
           
            
             
             
              
     
              
             
     

  
=> INSERT INTO t(n)
SELECT 0FROM generate_series(1,500);
-- the same value
=> SELECT page, hash_page_type(get_raw_page('t_n_idx', page))
FROM generate_series(0,4) page;
page | hash_page_type
−−−−−−+−−−−−−−−−−−−−−−−
0 | metapage
1 | bucket
2 | bucket
3 | bitmap
4 | overflow
(5 rows)
bucket 0bucket 0 bucket 1bucket 1
meta-
page bitmap bucket 1bucket 1bucket 1bucket 1
o
v
e
r
f
l
o
w
               
               
             
=> SELECT page, live_items, free_size, hasho_bucket
FROM (VALUES (1), (2), (4)) p(page),
hash_page_stats(get_raw_page('t_n_idx', page));
page | live_items | free_size | hasho_bucket
−−−−−−+−−−−−−−−−−−−+−−−−−−−−−−−+−−−−−−−−−−−−−−
1 | 0 | 8148 | 0
2 | 407 | 8 | 1
4 | 93 | 6288 | 1
(3 rows)
                
           
 
              
             
                
     

  
=> SELECT ntuples, ffactor, maxbucket, ovflpoint
FROM hash_metapage_info(get_raw_page('t_n_idx', 0));
ntuples | ffactor | maxbucket | ovflpoint
−−−−−−−−−+−−−−−−−−−+−−−−−−−−−−−+−−−−−−−−−−−
500 | 307 | 1 | 1
(1 row)
=> INSERT INTO t(n)
SELECT nFROM generate_series(1,115) n;
-- now values are different
=> SELECT ntuples, ffactor, maxbucket, ovflpoint
FROM hash_metapage_info(get_raw_page('t_n_idx', 0));
ntuples | ffactor | maxbucket | ovflpoint
−−−−−−−−−+−−−−−−−−−+−−−−−−−−−−−+−−−−−−−−−−−
615 | 307 | 2 | 2
(1 row)
             
                
  
=> SELECT page, hash_page_type(get_raw_page('t_n_idx', page))
FROM generate_series(0,6) page;
page | hash_page_type
−−−−−−+−−−−−−−−−−−−−−−−
0 | metapage
1 | bucket
2 | bucket
3 | bitmap
4 | overflow
5 | bucket
6 | unused
(7 rows)
bucket 0bucket 0 bucket 1bucket 1
meta-
page bitmap bucket 1bucket 1 bucket 2bucket 2bucket 1bucket 1
                 
        
=> SELECT page, live_items, free_size, hasho_bucket
FROM (VALUES (1), (2), (4), (5)) p(page),
hash_page_stats(get_raw_page('t_n_idx', page));

  
page | live_items | free_size | hasho_bucket
−−−−−−+−−−−−−−−−−−−+−−−−−−−−−−−+−−−−−−−−−−−−−−
1 | 27 | 7608 | 0
2 | 407 | 8 | 1
4 | 158 | 4988 | 1
5 | 23 | 7688 | 2
(4 rows)
              
           
              
            
    
             
  
=> SELECT maxbucket, highmask::bit(4), lowmask::bit(4)
FROM hash_metapage_info(get_raw_page('t_n_idx', 0));
maxbucket | highmask | lowmask
−−−−−−−−−−−+−−−−−−−−−−+−−−−−−−−−
2 | 0011 | 0001
(1 row)
             
            
              
                   
    
             
           
             
             
           
             
             
  
  
  

  
=> SELECT spares[2], spares[3]
FROM hash_metapage_info(get_raw_page('t_n_idx', 0));
spares | spares
−−−−−−−−+−−−−−−−−
2 | 2
(1 row)
          
=> SELECT mapp[1]
FROM hash_metapage_info(get_raw_page('t_n_idx', 0));
mapp
−−−−−−
3
(1 row)
bucket 0bucket 0 bucket 1bucket 1
meta-
page bitmap bucket 1bucket 1 bucket 2bucket 2
spares
mmap
             
              
         
            
            
             
            
                
   
         
=> CREATE INDEX ON flights USING hash(flight_no);
  

  
=> EXPLAIN (costs off)
SELECT *
FROM flights
WHERE flight_no = 'PG0001';
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Bitmap Heap Scan on flights
Recheck Cond: (flight_no = 'PG0001'::bpchar)
−> Bitmap Index Scan on flights_flight_no_idx
Index Cond: (flight_no = 'PG0001'::bpchar)
(4 rows)
  
              
          
                
             
             
             
             
               
          
=> SELECT opfname AS opfamily_name,
amproc::regproc AS opfamily_procedure
FROM pg_am am
JOIN pg_opfamily opf ON opfmethod = am.oid
JOIN pg_amproc amproc ON amprocfamily = opf.oid
WHERE amname = 'hash'
AND amprocnum = 1
ORDER BY opfamily_name, opfamily_procedure;
opfamily_name | opfamily_procedure
−−−−−−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−−−−−
aclitem_ops | hash_aclitem
array_ops | hash_array
bool_ops | hashchar
bpchar_ops | hashbpchar
bpchar_pattern_ops | hashbpchar
...

 
timetz_ops | timetz_hash
uuid_ops | uuid_hash
xid8_ops | hashint8
xid_ops | hashint4
(38 rows)
          
             
        
=> SELECT hashtext('one'), hashtext('two');
hashtext | hashtext
−−−−−−−−−−−−+−−−−−−−−−−−−
1793019229 | 1590507854
(1 row)
            
=> SELECT opfname AS opfamily_name,
left(amopopr::regoperator::text, 20) AS opfamily_operator
FROM pg_am am
JOIN pg_opfamily opf ON opfmethod = am.oid
JOIN pg_amop amop ON amopfamily = opf.oid
WHERE amname = 'hash'
ORDER BY opfamily_name, opfamily_operator;
opfamily_name | opfamily_operator
−−−−−−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−
aclitem_ops | =(aclitem,aclitem)
array_ops | =(anyarray,anyarray)
bool_ops | =(boolean,boolean)
...
uuid_ops | =(uuid,uuid)
xid8_ops | =(xid8,xid8)
xid_ops | =(xid,xid)
(48 rows)
 
             
  

  
  
=> SELECT a.amname, p.name, pg_indexam_has_property(a.oid, p.name)
FROM pg_am a, unnest(array[
'can_order', 'can_unique', 'can_multi_col',
'can_exclude', 'can_include'
]) p(name)
WHERE a.amname = 'hash';
amname | name | pg_indexam_has_property
−−−−−−−−+−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−−−
hash | can_order | f
hash | can_unique | f
hash | can_multi_col | f
hash | can_exclude | t
hash | can_include | f
(5 rows)
              
      
          
             
     
=> ALTER TABLE aircrafts_data
ADD CONSTRAINT unique_range EXCLUDE USING hash(range WITH =);
=> INSERT INTO aircrafts_data
VALUES ('744','{"ru": "Boeing 747-400"}',11100);
ERROR: conflicting key value violates exclusion constraint
"unique_range"
DETAIL: Key (range)=(11100) conflicts with existing key
(range)=(11100).
         
 
=> SELECT p.name, pg_index_has_property('flights_flight_no_idx', p.name)
FROM unnest(array[
'clusterable', 'index_scan', 'bitmap_scan', 'backward_scan'
]) p(name);

 
name | pg_index_has_property
−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−
clusterable | f
index_scan | t
bitmap_scan | t
backward_scan | t
(4 rows)
          
               
              
   
 
           
    
=> SELECT p.name,
pg_index_column_has_property('flights_flight_no_idx', 1, p.name)
FROM unnest(array[
'asc', 'desc', 'nulls_first', 'nulls_last', 'orderable',
'distance_orderable', 'returnable', 'search_array', 'search_nulls'
]) p(name);
name | pg_index_column_has_property
−−−−−−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
asc | f
desc | f
nulls_first | f
nulls_last | f
orderable | f
distance_orderable | f
returnable | f
search_array | f
search_nulls | f
(9 rows)
             
        

  
              
     
              
  
         

25
B-tree
 
           
              
            
            
    
            
        
AER OVBAER OVB
AER DME KZNAER DME KZN OVB ROV SVOOVB ROV SVO
AER
BZK
AER
BZK
DME
HMA
KJA
DME
HMA
KJA
KZN
LED
NUX
KZN
LED
NUX
OVB
OVS
PEE
OVB
OVS
PEE
ROV
SGC
ROV
SGC
SVO
SVX
VKO
SVO
SVX
VKO



  
            
            
         
     
              
          
            
          
            
             
             
       
             
              
               
               

   
 
              
         
             
            +

              
              
 
  

   
AER OVBAER OVB
AER DME KZNAER DME KZN OVB ROV SVOOVB ROV SVO
AER
BZK
AER
BZK
DME
HMA
KJA
DME
HMA
KJA
KZN
LED
NUX
KZN
LED
NUX
OVB
OVS
PEE
OVB
OVS
PEE
ROV
SGC
ROV
SGC
SVO
SVX
VKO
SVO
SVX
VKO
             
             
              
    
               
               
             
    
            
               
               
            
              
               
               
         
                  
             

  
              
               
         
              
 
 
         
             
            
      
              
 
AER OVBAER OVB
AER DME KZNAER DME KZN OVB ROV SVOOVB ROV SVO
AER
BZK
AER
BZK
DME
HMA
KJA
DME
HMA
KJA
KZN
LED
NUX
KZN
LED
NUX
OVB
OVS
PEE
OVB
OVS
PEE
ROV
SGC
ROV
SGC
SVO
SVX
VKO
SVO
SVX
VKO
              
     
 
       
            

   
            
          

AER OVBAER OVB
AER DME KZNAER DME KZN OVB ROV SVOOVB ROV SVO
AER
BZK
AER
BZK
DME
HMA
KJA
DME
HMA
KJA
KZN
LED
NUX
KZN
LED
NUX
OVB
OVS
PEE
OVB
OVS
PEE
ROV
SGC
ROV
SGC
SVO
SVX
VKO
SVO
SVX
VKO

            
              
              
               
            
              
                
               
              
                
               
     
               
             

  
               

AER OVB SVOAER OVB SVO
AER DME KZNAER DME KZN OVB ROVOVB ROV SVO TJMSVO TJM
AER
BZK
AER
BZK
DME
HMA
KJA
DME
HMA
KJA
KZN
LED
NUX
KZN
LED
NUX
OVB
OVS
PEE
OVB
OVS
PEE
ROV
RTW
SGC
ROV
RTW
SGC
SVO
SVX
SVO
SVX
TJM
VKO
TJM
VKO
           
            
       
              
            
             
              
                
  
             
              
              
                
       

  
metapage
AER OVB SVOAER OVB SVO
AER DME KZN OVBAER DME KZN OVB OVB ROV SVOOVB ROV SVO SVO TJMSVO TJM
AER
BZK
DME
AER
BZK
DME
DME
HMA
KJA
KZN
DME
HMA
KJA
KZN
KZN
LED
NUX
OVB
KZN
LED
NUX
OVB
OVB
OVS
PEE
ROV
OVB
OVS
PEE
ROV
ROV
RTW
SGC
SVO
ROV
RTW
SGC
SVO
SVO
SVX
TJM
SVO
SVX
TJM
TJM
VKO
TJM
VKO
0
1
2
               
            
                
    
             
            
            
=> SELECT root, level
FROM bt_metap('bookings_pkey');
root | level
−−−−−−+−−−−−−−
290 | 2
(1 row)

  
              
 
=> SELECT data
FROM bt_page_items('bookings_pkey',290)
WHERE itemoffset = 2;
data
−−−−−−−−−−−−−−−−−−−−−−−−−
0f 30 43 39 41 42 31 00
(1 row)
              
               
    
=> CREATE FUNCTION data_to_text(data text)
RETURNS text
AS $$
DECLARE
raw bytea := ('\x'||replace(data,' ',''))::bytea;
pos integer := 0;
len integer;
res text := '';
BEGIN
WHILE (octet_length(raw) > pos)
LOOP
len := (get_byte(raw,pos) - 3) / 2;
EXIT WHEN len <= 0;
IF pos > 0 THEN
res := res || ', ';
END IF;
res := res || (
SELECT string_agg( chr(get_byte(raw, i)),'')
FROM generate_series(pos+1,pos+len) i
);
pos := pos + len + 1;
END LOOP;
RETURN res;
END;
$$ LANGUAGE plpgsql;
           

  
=> SELECT itemoffset, ctid, data_to_text(data)
FROM bt_page_items('bookings_pkey',290);
itemoffset | ctid | data_to_text
−−−−−−−−−−−−+−−−−−−−−−−+−−−−−−−−−−−−−−
1 | (3,0) |
2 | (289,1) | 0C9AB1
3 | (575,1) | 192F03
4 | (860,1) | 25D715
5 | (1145,1) | 32785C
...
17 | (4565,1) | C993F6
18 | (4850,1) | D63931
19 | (5135,1) | E2CB14
20 | (5420,1) | EF6FEA
21 | (5705,1) | FC147D
(21 rows)
              
 
              
          
=> SELECT itemoffset, ctid, data_to_text(data)
FROM bt_page_items('bookings_pkey',5135);
itemoffset | ctid | data_to_text
−−−−−−−−−−−−+−−−−−−−−−−+−−−−−−−−−−−−−−
1 | (5417,1) | EF6FEA
2 | (5132,0) |
3 | (5133,1) | E2D71D
4 | (5134,1) | E2E2F4
5 | (5136,1) | E2EDE7
...
282 | (5413,1) | EF41BE
283 | (5414,1) | EF4D69
284 | (5415,1) | EF58D4
285 | (5416,1) | EF6410
(285 rows)
high key
              
               
             
       

  
            

=> SELECT itemoffset, ctid, data_to_text(data)
FROM bt_page_items('bookings_pkey',5133);
itemoffset | ctid | data_to_text
−−−−−−−−−−−−+−−−−−−−−−−−−−+−−−−−−−−−−−−−−
1 | (11921,1) | E2E2F4
2 | (11919,76) | E2D71D
3 | (11919,77) | E2D725
4 | (11919,78) | E2D72D
5 | (11919,79) | E2D733
...
363 | (11921,123) | E2E2C9
364 | (11921,124) | E2E2DB
365 | (11921,125) | E2E2DF
366 | (11921,126) | E2E2E5
367 | (11921,127) | E2E2ED
(367 rows)
                 
   
    
=> SELECT *FROM bookings
WHERE ctid = '(11919,77)';
book_ref | book_date | total_amount
−−−−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−
E2D725 | 2017−01−25 04:10:00+03 | 28000.00
(1 row)
             

=> EXPLAIN (costs off)
SELECT *FROM bookings
WHERE book_ref = 'E2D725';
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Index Scan using bookings_pkey on bookings
Index Cond: (book_ref = 'E2D725'::bpchar)
(2 rows)

  
 
            
            
            
            
      
           
              
           
            
             
 
          
              
        
            
          
 
            
            
              
          
          
             
         
          
  
          
          

  
  


  
           
     
=> CREATE INDEX ON tickets(book_ref);
=> SELECT allequalimage FROM bt_metap('tickets_book_ref_idx');
allequalimage
−−−−−−−−−−−−−−−
t
(1 row)
              
             
   
=> SELECT itemoffset, htid, left(tids::text,27) tids,
data_to_text(data) AS data
FROM bt_page_items('tickets_book_ref_idx',1)
WHERE itemoffset > 1;
itemoffset | htid | tids | data
−−−−−−−−−−−−+−−−−−−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+−−−−−−−−
2 | (32965,40) | | 000004
3 | (47429,51) | | 00000F
4 | (3648,56) | {"(3648,56)","(3648,57)"} | 000010
5 | (6498,47) | | 000012
...
271 | (21492,46) | | 000890
272 | (26601,57) | {"(26601,57)","(26601,58)"} | 0008AC
273 | (25669,37) | | 0008B6
(272 rows)
      
           
             
              
    
             
             
             
       

  
             
    
                
             
              
     
               
          
=> CREATE INDEX tickets_bref_name_idx
ON tickets(book_ref, passenger_name);
=> SELECT itemoffset, ctid, data_to_text(data)
FROM bt_page_items('tickets_bref_name_idx',229)
WHERE itemoffset BETWEEN 8AND 13;
itemoffset | ctid | data_to_text
−−−−−−−−−−−−+−−−−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−−−−−−
8 | (1607,1) | 1A98A0
9 | (1833,2) | 1E57D1, SVETLANA MAKSIMOVA
10 | (2054,1) | 220797
11 | (2282,1) | 25DB06
12 | (2509,2) | 299FE4, YURIY AFANASEV
13 | (2736,1) | 2D62C9
(6 rows)
           
             
           
       
  
 
              
           
  

  
             
         
             
           
            
         
=> SELECT amopopr::regoperator AS opfamily_operator,
amopstrategy
FROM pg_am am
JOIN pg_opfamily opf ON opfmethod = am.oid
JOIN pg_amop amop ON amopfamily = opf.oid
WHERE amname = 'btree'
AND opfname = 'bool_ops'
ORDER BY amopstrategy;
opfamily_operator | amopstrategy
−−−−−−−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−
<(boolean,boolean) | 1
<=(boolean,boolean) | 2
=(boolean,boolean) | 3
>=(boolean,boolean) | 4
>(boolean,boolean) | 5
(5 rows)
           
   
 
    
 
    
 
          
                
       




  
           

           
         
            
             
        
       
=> CREATE TYPE capacity_units AS ENUM (
'B', 'kB', 'MB', 'GB', 'TB', 'PB'
);
=> CREATE TYPE capacity AS (
amount integer,
unit capacity_units
);
              
=> CREATE TABLE test AS
SELECT ( (random()*1023)::integer, u.unit )::capacity AS cap
FROM generate_series(1,100),
unnest(enum_range(NULL::capacity_units)) AS u(unit);
            
          
=> SELECT *FROM test ORDER BY cap;
cap
−−−−−−−−−−−
(1,B)
(3,GB)
(4,MB)
(9,kB)
...
(1017,kB)
(1017,GB)
(1018,PB)
(1020,MB)
(600 rows)


  
            
      
=> CREATE FUNCTION capacity_to_bytes(a capacity) RETURNS numeric
AS $$
SELECT a.amount::numeric *
1024::numeric ^ ( array_position(enum_range(a.unit), a.unit) - 1 );
$$ LANGUAGE sql STRICT IMMUTABLE;
=> SELECT capacity_to_bytes('(1,kB)'::capacity);
capacity_to_bytes
−−−−−−−−−−−−−−−−−−−−−−−
1024.0000000000000000
(1 row)
       
=> CREATE FUNCTION capacity_cmp(a capacity, b capacity)
RETURNS integer
AS $$
SELECT sign(capacity_to_bytes(a) - capacity_to_bytes(b));
$$ LANGUAGE sql STRICT IMMUTABLE;
            
          
=> CREATE FUNCTION capacity_lt(a capacity, b capacity) RETURNS boolean
AS $$
BEGIN
RETURN capacity_cmp(a,b) < 0;
END;
$$ LANGUAGE plpgsql IMMUTABLE STRICT;
=> CREATE OPERATOR #<# (
LEFTARG = capacity,
RIGHTARG = capacity,
FUNCTION = capacity_lt
);
        
=> CREATE FUNCTION capacity_le(a capacity, b capacity) RETURNS boolean
AS $$
BEGIN
RETURN capacity_cmp(a,b) <= 0;
END;
$$ LANGUAGE plpgsql IMMUTABLE STRICT;

  
=> CREATE OPERATOR #<=# (
LEFTARG = capacity,
RIGHTARG = capacity,
FUNCTION = capacity_le
);
=> CREATE FUNCTION capacity_eq(a capacity, b capacity) RETURNS boolean
AS $$
BEGIN
RETURN capacity_cmp(a,b) = 0;
END;
$$ LANGUAGE plpgsql IMMUTABLE STRICT;
=> CREATE OPERATOR #=# (
LEFTARG = capacity,
RIGHTARG = capacity,
FUNCTION = capacity_eq,
MERGES
-- can be used in merge joins
);
=> CREATE FUNCTION capacity_ge(a capacity, b capacity) RETURNS boolean
AS $$
BEGIN
RETURN capacity_cmp(a,b) >= 0;
END;
$$ LANGUAGE plpgsql IMMUTABLE STRICT;
=> CREATE OPERATOR #>=# (
LEFTARG = capacity,
RIGHTARG = capacity,
FUNCTION = capacity_ge
);
=> CREATE FUNCTION capacity_gt(a capacity, b capacity) RETURNS boolean
AS $$
BEGIN
RETURN capacity_cmp(a,b) > 0;
END;
$$ LANGUAGE plpgsql IMMUTABLE STRICT;
=> CREATE OPERATOR #># (
LEFTARG = capacity,
RIGHTARG = capacity,
FUNCTION = capacity_gt
);
     

  
=> SELECT (1,'MB')::capacity #># (512, 'kB')::capacity;
?column?
−−−−−−−−−−
t
(1 row)
            
=> CREATE OPERATOR CLASS capacity_ops
DEFAULT FOR TYPE capacity
-- to be used by default
USING btree AS
OPERATOR 1 #<#,
OPERATOR 2 #<=#,
OPERATOR 3 #=#,
OPERATOR 4 #>=#,
OPERATOR 5 #>#,
FUNCTION 1 capacity_cmp(capacity,capacity);
=> SELECT *FROM test ORDER BY cap;
cap
−−−−−−−−−−−
(1,B)
(21,B)
(27,B)
(35,B)
(46,B)
...
(1002,PB)
(1013,PB)
(1014,PB)
(1014,PB)
(1018,PB)
(600 rows)
              
      
=> CREATE INDEX ON test(cap);
=> SELECT *FROM test WHERE cap #<# (100,'B')::capacity ORDER BY cap;
cap
−−−−−−−−
(1,B)
(21,B)
(27,B)
(35,B)

  
(46,B)
(57,B)
(68,B)
(70,B)
(72,B)
(76,B)
(78,B)
(94,B)
(12 rows)
=> EXPLAIN (costs off) SELECT *
FROM test WHERE cap #<# (100,'B')::capacity ORDER BY cap;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Index Only Scan using test_cap_idx on test
Index Cond: (cap #<# '(100,B)'::capacity)
(2 rows)
           
    
   
       
             
             
             
          
              
             
              
 
                 
           
=> SELECT itemoffset, data_to_text(data)
FROM bt_page_items('tickets_bref_name_idx',1)
WHERE itemoffset > 1;

  
itemoffset | data_to_text
−−−−−−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
2 | 000004, PETR MAKAROV
3 | 00000F, ANNA ANTONOVA
4 | 000010, ALEKSANDR SOKOLOV
5 | 000010, LYUDMILA BOGDANOVA
6 | 000012, TAMARA ZAYCEVA
7 | 000026, IRINA PETROVA
8 | 00002D, ALEKSANDR SMIRNOV
...
187 | 0003EF, VLADIMIR CHERNOV
188 | 00040C, ANTONINA KOROLEVA
189 | 00040C, DMITRIY FEDOROV
190 | 00041E, EGOR FEDOROV
191 | 00041E, ILYA STEPANOV
192 | 000447, VIKTOR VASILEV
193 | 00044D, NADEZHDA KULIKOVA
(192 rows)
             
         
=> EXPLAIN (costs off) SELECT *
FROM tickets
WHERE book_ref = '000010';
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Index Scan using tickets_book_ref_idx on tickets
Index Cond: (book_ref = '000010'::bpchar)
(2 rows)
=> EXPLAIN (costs off) SELECT *
FROM tickets
WHERE book_ref = '000010' AND passenger_name = 'LYUDMILA BOGDANOVA';
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Index Scan using tickets_bref_name_idx on tickets
Index Cond: ((book_ref = '000010'::bpchar) AND (passenger_name...
(2 rows)
               
=> EXPLAIN (costs off) SELECT *
FROM tickets
WHERE passenger_name = 'LYUDMILA BOGDANOVA';

  
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Gather
Workers Planned: 2
−> Parallel Seq Scan on tickets
Filter: (passenger_name = 'LYUDMILA BOGDANOVA'::text)
(4 rows)
              
            
      
              
          
           
   
   
   
               
              
             
   
=> CREATE INDEX tickets_name_bref_idx
ON tickets(passenger_name, book_ref);
=> SELECT itemoffset, data_to_text(data)
FROM bt_page_items('tickets_name_bref_idx',1)
WHERE itemoffset > 1;
itemoffset | data_to_text
−−−−−−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
2 | ADELINA ABRAMOVA, E37EDB
3 | ADELINA AFANASEVA, 1133B7
4 | ADELINA AFANASEVA, 4F3370
5 | ADELINA AKIMOVA, 7D2881
6 | ADELINA ALEKSANDROVA, 3C3ADD
7 | ADELINA ALEKSANDROVA, 52801E
...
  


  
185 | ADELINA LEBEDEVA, 0A00E3
186 | ADELINA LEBEDEVA, DAEADE
187 | ADELINA LEBEDEVA, DFD7E5
188 | ADELINA LOGINOVA, 8022F3
189 | ADELINA LOGINOVA, EE67B9
190 | ADELINA LUKYANOVA, 292786
191 | ADELINA LUKYANOVA, 54D3F9
(190 rows)
=> EXPLAIN (costs off) SELECT *FROM tickets
WHERE passenger_name = 'LYUDMILA BOGDANOVA';
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Bitmap Heap Scan on tickets
Recheck Cond: (passenger_name = 'LYUDMILA BOGDANOVA'::text)
−> Bitmap Index Scan on tickets_name_bref_idx
Index Cond: (passenger_name = 'LYUDMILA BOGDANOVA'::text)
(4 rows)
              
            
                 
             
    
              
      
=> EXPLAIN (costs off) SELECT *
FROM tickets
ORDER BY passenger_name, book_ref;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Index Scan using tickets_name_bref_idx on tickets
(1 row)
=> EXPLAIN (costs off) SELECT *
FROM tickets ORDER BY passenger_name DESC, book_ref DESC;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Index Scan Backward using tickets_name_bref_idx on tickets
(1 row)
                
              

  
                
   
=> EXPLAIN (costs off) SELECT *
FROM tickets ORDER BY passenger_name ASC, book_ref DESC;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Incremental Sort
Sort Key: passenger_name, book_ref DESC
Presorted Key: passenger_name
−> Index Scan using tickets_name_bref_idx on tickets
(4 rows)
              
           
                  
               
           
               
   
=> EXPLAIN (costs off) SELECT *
FROM tickets ORDER BY passenger_name NULLS FIRST, book_ref DESC;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Gather Merge
Workers Planned: 2
−> Sort
Sort Key: passenger_name NULLS FIRST, book_ref DESC
−> Parallel Seq Scan on tickets
(5 rows)
              
=> CREATE INDEX tickets_name_bref_idx2
ON tickets(passenger_name NULLS FIRST, book_ref DESC);
=> EXPLAIN (costs off) SELECT *
FROM tickets ORDER BY passenger_name NULLS FIRST, book_ref DESC;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Index Scan using tickets_name_bref_idx2 on tickets
(1 row)

  
 
         
  
=> SELECT a.amname, p.name, pg_indexam_has_property(a.oid, p.name)
FROM pg_am a, unnest(array[
'can_order', 'can_unique', 'can_multi_col',
'can_exclude', 'can_include'
]) p(name)
WHERE a.amname = 'btree';
amname | name | pg_indexam_has_property
−−−−−−−−+−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−−−
btree | can_order | t
btree | can_unique | t
btree | can_multi_col | t
btree | can_exclude | t
btree | can_include | t
(5 rows)
              
 
           
              
          
           
      
            
  
 
=> SELECT p.name, pg_index_has_property('flights_pkey', p.name)
FROM unnest(array[
'clusterable', 'index_scan', 'bitmap_scan', 'backward_scan'
]) p(name);

 
name | pg_index_has_property
−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−
clusterable | t
index_scan | t
bitmap_scan | t
backward_scan | t
(4 rows)
      
             
            
  
=> EXPLAIN (costs off) SELECT *
FROM bookings ORDER BY book_ref DESC;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Index Scan Backward using bookings_pkey on bookings
(1 row)
 
=> SELECT p.name,
pg_index_column_has_property('flights_pkey', 1, p.name)
FROM unnest(array[
'asc', 'desc', 'nulls_first', 'nulls_last', 'orderable',
'distance_orderable', 'returnable', 'search_array', 'search_nulls'
]) p(name);
name | pg_index_column_has_property
−−−−−−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
asc | t
desc | f
nulls_first | f
nulls_last | t
orderable | t
distance_orderable | f
returnable | t
search_array | t
search_nulls | t
(9 rows)

  
            
             
            
      
          
          
     
            
          


26
GiST
 
          
            
           
             
            
             
         
           
           
             
            
          
            
             
           
            
       
              
            
               
  



  
             
              
               
             
   
              
     
            
          
            
            
 
             
            
             
            
      
              
            
            
             
             
              
 
                
           
             
            
  
  
  

   
             
               
          
            
          

   
           
              
           
           
             
  
             
             
         
            
            
   
           
             
      
             
            
            90
             
       
         

  
=> CREATE TABLE airports_big AS
SELECT *FROM airports_data;
=> COPY airports_big FROM
'/home/student/internals/airports/extra_airports.copy';
=> CREATE INDEX airports_gist_idx ON airports_big
USING gist(coordinates) WITH (fillfactor=10);
           
 
         

   
              
    
             

             
            
 
         
              
                
      
       
=> SELECT ctid, keys
FROM gist_page_items(
get_raw_page('airports_gist_idx', 0), 'airports_gist_idx'
);

  
ctid | keys
−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
(207,65535) | (coordinates)=((50.84510040283203,78.246101379395))
(400,65535) | (coordinates)=((179.951004028,73.51780700683594))
(206,65535) | (coordinates)=((−1.5908199548721313,40.63980103))
(466,65535) | (coordinates)=((−1.0334999561309814,82.51779937740001))
(4 rows)
              
           
             
             
            
     
 
            
      
=> SELECT amprocnum, amproc::regproc
FROM pg_am am
JOIN pg_opclass opc ON opcmethod = am.oid
JOIN pg_amproc amop ON amprocfamily = opcfamily
WHERE amname = 'gist'
AND opcname = 'point_ops'
ORDER BY amprocnum;
amprocnum | amproc
−−−−−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−−
1 | gist_point_consistent
2 | gist_box_union
3 | gist_point_compress
5 | gist_box_penalty
6 | gist_box_picksplit
7 | gist_box_same
8 | gist_point_distance
9 | gist_point_fetch
11 | gist_point_sortsupport
(9 rows)



   
      
        
    
            

          
       
       
=> SELECT amopopr::regoperator, amopstrategy AS st, oprcode::regproc,
left(obj_description(opr.oid, 'pg_operator'), 19) description
FROM pg_am am
JOIN pg_opclass opc ON opcmethod = am.oid
JOIN pg_amop amop ON amopfamily = opcfamily
JOIN pg_operator opr ON opr.oid = amopopr
WHERE amname = 'gist'
AND opcname = 'point_ops'
ORDER BY amopstrategy;
amopopr | st | oprcode | description
−−−−−−−−−−−−−−−−−−−+−−−−+−−−−−−−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−−−−−−
<<(point,point) | 1 | point_left | is left of
>>(point,point) | 5 | point_right | is right of
~=(point,point) | 6 | point_eq | same as
<<|(point,point) | 10 | point_below | is below
|>>(point,point) | 11 | point_above | is above
<−>(point,point) | 15 | point_distance | distance between
<@(point,box) | 28 | on_pb | point inside box
<^(point,point) | 29 | point_below | deprecated, use <<|
>^(point,point) | 30 | point_above | deprecated, use |>>
<@(point,polygon) | 48 | pt_contained_poly | is contained by
<@(point,circle) | 68 | pt_contained_circle | is contained by
(11 rows)
             
           
            
       
            
          


  
              
          
    
          
            
           
  
   
               

              

=> SELECT airport_code, airport_name->>'en'
FROM airports_big
WHERE coordinates <@ '<(37.622513,55.753220),1.0>'::circle;
airport_code | ?column?
−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
SVO | Sheremetyevo International Airport
VKO | Vnukovo International Airport
DME | Domodedovo International Airport
BKA | Bykovo Airport
ZIA | Zhukovsky International Airport
CKL | Chkalovskiy Air Base
OSF | Ostafyevo International Airport
(7 rows)
=> EXPLAIN (costs off) SELECT airport_code
FROM airports_big
WHERE coordinates <@ '<(37.622513,55.753220),1.0>'::circle;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Bitmap Heap Scan on airports_big
Recheck Cond: (coordinates <@ '<(37.622513,55.75322),1>'::circle)
−> Bitmap Index Scan on airports_gist_idx
Index Cond: (coordinates <@ '<(37.622513,55.75322),1>'::ci...
(4 rows)

   
            
 
0
1
2
3
4
5
6
7
8
9
012345678 9
             
0,0–3,4 5,3–9,90,0–3,4 5,3–9,9
0,0–3,2 0,3–3,40,0–3,2 0,3–3,4 5,3–8,5 6,6–9,95,3–8,5 6,6–9,9
0,0 1,2 3,10,0 1,2 3,1 0,4 3,30,4 3,3 5,3 8,55,3 8,5 6,6 8,9 9,76,6 8,9 9,7
          
         
              
            
          
  

  
             
  
0
1
2
3
4
5
6
7
8
9
012345678 9
0,0–3,4 5,3–9,90,0–3,4 5,3–9,9
0,0–3,2 0,3–3,40,0–3,2 0,3–3,4 5,3–8,5 6,6–9,95,3–8,5 6,6–9,9
0,0 1,2 3,10,0 1,2 3,1 0,4 3,30,4 3,3 5,3 8,55,3 8,5 6,6 8,9 9,76,6 8,9 9,7
             
               
 
           
      
                
        
           
          

   
  
              
           
          
            
             
            
             
      
         
=> SELECT airport_code, airport_name->>'en'
FROM airports_big
ORDER BY coordinates <-> '(40.926780,57.767943)'::point
LIMIT 10;
airport_code | ?column?
−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
KMW | Kostroma Sokerkino Airport
IAR | Tunoshna Airport
IWA | Ivanovo South Airport
VGD | Vologda Airport
RYB | Staroselye Airport
GOJ | Nizhny Novgorod Strigino International Airport
CEE | Cherepovets Airport
CKL | Chkalovskiy Air Base
ZIA | Zhukovsky International Airport
BKA | Bykovo Airport
(10 rows)
=> EXPLAIN (costs off) SELECT airport_code
FROM airports_big
ORDER BY coordinates <-> '(40.926780,57.767943)'::point
LIMIT 5;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Limit
−> Index Scan using airports_gist_idx on airports_big
Order By: (coordinates <−> '(40.92678,57.767943)'::point)
(3 rows)
              
       

  
             
               
             
              
               
  
=> SELECT amopopr::regoperator, amoppurpose, amopstrategy
FROM pg_am am
JOIN pg_opclass opc ON opcmethod = am.oid
JOIN pg_amop amop ON amopfamily = opcfamily
WHERE amname = 'gist'
AND opcname = 'point_ops'
ORDER BY amopstrategy;
amopopr | amoppurpose | amopstrategy
−−−−−−−−−−−−−−−−−−−+−−−−−−−−−−−−−+−−−−−−−−−−−−−−
<<(point,point) | s | 1
>>(point,point) | s | 5
~=(point,point) | s | 6
<<|(point,point) | s | 10
|>>(point,point) | s | 11
<−>(point,point) | o | 15
<@(point,box) | s | 28
<^(point,point) | s | 29
>^(point,point) | s | 30
<@(point,polygon) | s | 48
<@(point,circle) | s | 68
(11 rows)
           
               
           
           
            
 
              
               
        
  

   
          

            
            
               
           
                
 
            
0
1
2
3
4
5
6
7
8
9
012345678 9
             
              
              
               
  
             
           
               
              
                 
  
  

  
0,0–3,4 5,3–9,90,0–3,4 5,3–9,9
0,0–3,2 0,3–3,40,0–3,2 0,3–3,4 5,3–8,5 6,6–9,95,3–8,5 6,6–9,9
0,0 1,2 3,10,0 1,2 3,1 0,4 3,30,4 3,3 5,3 8,55,3 8,5 6,6 8,9 9,76,6 8,9 9,7
5.0 0.0
3.0 0.0
2.0 2.2 3.2
               
            
               
                 
                 
          
0,0–3,4 5,3–9,90,0–3,4 5,3–9,9
0,0–3,2 0,3–3,40,0–3,2 0,3–3,4 5,3–8,5 6,6–9,95,3–8,5 6,6–9,9
0,0 1,2 3,10,0 1,2 3,1 0,4 3,30,4 3,3 5,3 8,55,3 8,5 6,6 8,9 9,76,6 8,9 9,7
5.0 0.0
3.0 0.0
2.0 2.2 3.25.1 3.6

   
          
            
             
      

               
              
    
             
            
             
   
0
1
2
3
4
5
6
7
8
9
012345678 9
0
1
2
3
4
5
6
7
8
9
012345678 9
               
             
              
  

  
           
          
    
0
1
2
3
4
5
6
7
8
9
012345678 9
 
        
            
             
  
           
 
           
         
   
            
               
 
  

   
       
   
      
             
           
         
=> ALTER TABLE airports_data ADD EXCLUDE
USING gist (circle(coordinates,0.2) WITH &&);
=> INSERT INTO airports_data(
airport_code, airport_name, city, coordinates, timezone
)VALUES (
'ZIA', '{}', '{"en": "Moscow"}', point(38.1517, 55.5533),
'Europe/Moscow'
);
ERROR: conflicting key value violates exclusion constraint
"airports_data_circle_excl"
DETAIL: Key (circle(coordinates, 0.2::double
precision))=(<(38.1517,55.5533),0.2>) conflicts with existing key
(circle(coordinates, 0.2::double
precision))=(<(37.90629959106445,55.40879821777344),0.2>).
             
         
             
               
            
               
         
              
      
=> ALTER TABLE airports_data
DROP CONSTRAINT airports_data_circle_excl;
-- delete old data
=> ALTER TABLE airports_data ADD EXCLUDE USING gist (
circle(coordinates,0.2) WITH &&,
(city->>'en') WITH !=
);

  
ERROR: data type text has no default operator class for access
method "gist"
HINT: You must specify an operator class for the index or define a
default operator class for the data type.
            
              
          
       
=> CREATE EXTENSION btree_gist;
=> ALTER TABLE airports_data ADD EXCLUDE USING gist (
circle(coordinates,0.2) WITH &&,
(city->>'en') WITH !=
);
ALTER TABLE
           
          
=> INSERT INTO airports_data(
airport_code, airport_name, city, coordinates, timezone
)VALUES (
'ZIA', '{}', '{"en": "Zhukovsky"}', point(38.1517, 55.5533),
'Europe/Moscow'
);
ERROR: conflicting key value violates exclusion constraint
"airports_data_circle_expr_excl"
DETAIL: Key (circle(coordinates, 0.2::double precision), (city −>>
'en'::text))=(<(38.1517,55.5533),0.2>, Zhukovsky) conflicts with
existing key (circle(coordinates, 0.2::double precision), (city −>>
'en'::text))=(<(37.90629959106445,55.40879821777344),0.2>, Moscow).
            
=> INSERT INTO airports_data(
airport_code, airport_name, city, coordinates, timezone
)VALUES (
'ZIA', '{}', '{"en": "Moscow"}', point(38.1517, 55.5533),
'Europe/Moscow'
);
INSERT 0 1

   
            
            
              
             
 

          
=> SELECT a.amname, p.name, pg_indexam_has_property(a.oid, p.name)
FROM pg_am a, unnest(array[
'can_order', 'can_unique', 'can_multi_col',
'can_exclude', 'can_include'
]) p(name)
WHERE a.amname = 'gist';
amname | name | pg_indexam_has_property
−−−−−−−−+−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−−−
gist | can_order | f
gist | can_unique | f
gist | can_multi_col | t
gist | can_exclude | t
gist | can_include | t
(5 rows)
      
        
                 

         
=> SELECT p.name, pg_index_has_property('airports_gist_idx', p.name)
FROM unnest(array[
'clusterable', 'index_scan', 'bitmap_scan', 'backward_scan'
]) p(name);

  
name | pg_index_has_property
−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−
clusterable | t
index_scan | t
bitmap_scan | t
backward_scan | f
(4 rows)
      
           
           
           
      
=> SELECT p.name,
pg_index_column_has_property('airports_gist_idx', 1, p.name)
FROM unnest(array[
'orderable', 'search_array', 'search_nulls'
]) p(name);
name | pg_index_column_has_property
−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
orderable | f
search_array | f
search_nulls | t
(3 rows)
    
              
            
              
          

=> SELECT p.name,
pg_index_column_has_property('airports_gist_idx', 1, p.name)
FROM unnest(array[
'returnable', 'distance_orderable'
]) p(name);

    
name | pg_index_column_has_property
−−−−−−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
returnable | t
distance_orderable | t
(2 rows)
          
             
             
           
           
             
     
=> CREATE TABLE reservations(during tsrange);
=> CREATE INDEX ON reservations USING gist(during);
=> SELECT p.name,
pg_index_column_has_property('reservations_during_idx', 1, p.name)
FROM unnest(array[
'returnable', 'distance_orderable'
]) p(name);
name | pg_index_column_has_property
−−−−−−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
returnable | t
distance_orderable | f
(2 rows)
    
  
           
     


  
            
           
             
    
=> SET default_text_search_config = english;
=> SELECT to_tsvector(
'No one can tell me, nobody knows, ' ||
'Where the wind comes from, where the wind goes.'
);
to_tsvector
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
'come':11 'goe':16 'know':7 'nobodi':6 'one':2 'tell':4 'wind':10,15
(1 row)
             
             
    
            
           
     
=> SELECT to_tsquery('wind & (comes | goes)');
to_tsquery
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
'wind' & ( 'come' | 'goe' )
(1 row)
           
=> SELECT amopopr::regoperator, oprcode::regproc, amopstrategy
FROM pg_am am
JOIN pg_opclass opc ON opcmethod = am.oid
JOIN pg_amop amop ON amopfamily = opcfamily
JOIN pg_operator opr ON opr.oid = amopopr
WHERE amname = 'gist'
AND opcname = 'tsvector_ops'
ORDER BY amopstrategy;
amopopr | oprcode | amopstrategy
−−−−−−−−−−−−−−−−−−−−−−+−−−−−−−−−−−−−+−−−−−−−−−−−−−−
@@(tsvector,tsquery) | ts_match_vq | 1
(1 row)

    
           

=> SELECT to_tsvector('Where the wind comes from, where the wind goes')
@@ to_tsquery('wind & coming');
?column?
−−−−−−−−−−
t
(1 row)
              
      
  
              
           
             
              
              
               
              
              
      
          
             
            
        
=> CREATE TABLE ts(
doc text,
doc_tsv tsvector GENERATED ALWAYS AS (
to_tsvector('pg_catalog.english', doc)
)STORED
);




  
=> CREATE INDEX ts_gist_idx ON ts
USING gist(doc_tsv);
            
english         
              
           
          
   
=> INSERT INTO ts(doc)
VALUES
('Old MacDonald had a farm'),
('And on his farm he had some cows'),
('Here a moo, there a moo'),
('Everywhere a moo moo'),
('Old MacDonald had a farm'),
('And on his farm he had some chicks'),
('Here a cluck, there a cluck'),
('Everywhere a cluck cluck'),
('Old MacDonald had a farm'),
('And on his farm he had some pigs'),
('Here an oink, there an oink'),
('Everywhere an oink oink')
RETURNING doc_tsv;
doc_tsv
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
'farm':5 'macdonald':2 'old':1
'cow':8 'farm':4
'moo':3,6
'everywher':1 'moo':3,4
'farm':5 'macdonald':2 'old':1
'chick':8 'farm':4
'cluck':3,6
'cluck':3,4 'everywher':1
'farm':5 'macdonald':2 'old':1
'farm':4 'pig':8
'oink':3,6
'everywher':1 'oink':3,4
(12 rows)
INSERT 0 12
              
           

    
           
              
            
   
            
         
      
cow, everywher,
farm, macdonald,
moo, old
chick, cluck,
everywher, farm,
oink, pig
cow, everywher,
farm, macdonald,
moo, old
chick, cluck,
everywher, farm,
oink, pig
farm,
macdonald, old
cow, everywher,
farm, moo
farm,
macdonald, old
cow, everywher,
farm, moo
chick, cluck,
everywher, farm
everywher, farm,
oink, pig
chick, cluck,
everywher, farm
everywher, farm,
oink, pig
farm, macdonald, old
farm, macdonald, old
farm, macdonald, old
farm, macdonald, old
farm, macdonald, old
farm, macdonald, old
cow, farm
moo
everywher, moo
cow, farm
moo
everywher, moo
chick, farm
cluck
cluck, everywher
chick, farm
cluck
cluck, everywher
farm, pig
oink
everywher, oink
farm, pig
oink
everywher, oink
         
              
 
           
             
           
             

  
cow, everywher,
farm, macdonald,
moo, old
chick, cluck,
everywher, farm,
oink, pig
cow, everywher,
farm, macdonald,
moo, old
chick, cluck,
everywher, farm,
oink, pig
farm,
macdonald, old
cow, everywher,
farm, moo
farm,
macdonald, old
cow, everywher,
farm, moo
chick, cluck,
everywher, farm
everywher, farm,
oink, pig
chick, cluck,
everywher, farm
everywher, farm,
oink, pig
farm, macdonald, old
farm, macdonald, old
farm, macdonald, old
farm, macdonald, old
farm, macdonald, old
farm, macdonald, old
cow, farm
moo
everywher, moo
cow, farm
moo
everywher, moo
chick, farm
cluck
cluck, everywher
chick, farm
cluck
cluck, everywher
farm, pig
oink
everywher, oink
farm, pig
oink
everywher, oink
          
              
            
                   
     
            
    
   
1000000
   
0001000
   
0000010
 
0010000

0000100

0100000

0000100

0000010

0000001

0010000

    
      
0100101
           
0000110
    
0000100
  
0010100
       
1000100
   
0001000
  
0011000
       
0010100
     
0000010
   
0010010
        
0110111 10111100110111 1011110
0100101 00101100100101 0010110 1011100 00101101011100 0010110
0100101
0100101
0100101
0100101
0100101
0100101
0000110
0000100
0010100
0000110
0000100
0010100
1000100
0001000
0011000
1000100
0001000
0011000
0010100
0000010
0010010
0010100
0000010
0010010
            
              
           
              
            
         
           
              

  
           
         
0110111 10111100110111 1011110
0100101 00101100100101 0010110 1011100 00101101011100 0010110
0100101
0100101
0100101
0100101
0100101
0100101
0000110
0000100
0010100
0000110
0000100
0010100
1000100
0001000
0011000
1000100
0001000
0011000
0010100
0000010
0010010
0010100
0000010
0010010
             
            
              
              
            
             
             

              
               
             
 
CREATE INDEX ... USING gist(column tsvector_ops(siglen = size));
  

    
         
     
           
             
           
          
    
             
            
             
=> ALTER TABLE mail_messages ADD COLUMN tsv tsvector
GENERATED ALWAYS AS ( to_tsvector(
'pg_catalog.english', subject||' '||author||' '||body_plain
) ) STORED;
NOTICE: word is too long to be indexed
DETAIL: Words longer than 2047 characters are ignored.
...
NOTICE: word is too long to be indexed
DETAIL: Words longer than 2047 characters are ignored.
ALTER TABLE
=> CREATE INDEX mail_gist_idx ON mail_messages USING gist(tsv);
=> SELECT pg_size_pretty(pg_relation_size('mail_gist_idx'));
pg_size_pretty
−−−−−−−−−−−−−−−−
127 MB
(1 row)
             
                
=> EXPLAIN (analyze, costs off, timing off, summary off)
SELECT *
FROM mail_messages
WHERE tsv @@ to_tsquery('magic & value');
  


  
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Index Scan using mail_gist_idx on mail_messages
(actual rows=898 loops=1)
Index Cond: (tsv @@ to_tsquery('magic & value'::text))
Rows Removed by Index Recheck: 7859
(4 rows)
            
             
           
   
=> DROP INDEX mail_messages_tsv_idx;
=> CREATE INDEX ON mail_messages
USING gist(tsv tsvector_ops(siglen=248));
=> SELECT pg_size_pretty(pg_relation_size('mail_messages_tsv_idx'));
pg_size_pretty
−−−−−−−−−−−−−−−−
139 MB
(1 row)
=> EXPLAIN (analyze, costs off, timing off, summary off)
SELECT *
FROM mail_messages
WHERE tsv @@ to_tsquery('magic & value');
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Index Scan using mail_messages_tsv_idx on mail_messages
(actual rows=898 loops=1)
Index Cond: (tsv @@ to_tsquery('magic & value'::text))
Rows Removed by Index Recheck: 2060
(4 rows)

              
           


   
=> SELECT p.name,
pg_index_column_has_property('mail_messages_tsv_idx', 1, p.name)
FROM unnest(array[
'returnable', 'distance_orderable'
]) p(name);
name | pg_index_column_has_property
−−−−−−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
returnable | f
distance_orderable | f
(2 rows)
            
              
          
          
   
           
               
         
             
     
           
           
          
    
          
           
 
         
          
      


  
           
       
         
            
           
           
             
          
           
            
           
             
 
             
    
          
             
           
           
          
 
           
            
             
           
           
         
      



   
           
        
   
          
        

27
SP-GiST
 
             
               
             
            
             
     
             
           
          
            
    
         
             
                
               
               
                
 
             
               



   
             
 
              
 
           
            
             
            
  
             
            
                
          
           
             
   
           
            
              
              
               
              
           

        
   
           
           
  

  
              
      
        
          

   
           
              
           
         80   
  
=> CREATE INDEX airports_quad_idx ON airports_big
USING spgist(coordinates) WITH (fillfactor = 10);
       
 
        
      
             
    



  
=> SELECT amprocnum, amproc::regproc
FROM pg_am am
JOIN pg_opclass opc ON opcmethod = am.oid
JOIN pg_amproc amop ON amprocfamily = opcfamily
WHERE amname = 'spgist'
AND opcname = 'quad_point_ops'
ORDER BY amprocnum;
amprocnum | amproc
−−−−−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−−−−−
1 | spg_quad_config
2 | spg_quad_choose
3 | spg_quad_picksplit
4 | spg_quad_inner_consistent
5 | spg_quad_leaf_consistent
(5 rows)
     
           
 
       
         
           
   
          
    
     
          
=> SELECT amopopr::regoperator, oprcode::regproc, amopstrategy
FROM pg_am am
JOIN pg_opclass opc ON opcmethod = am.oid
JOIN pg_amop amop ON amopfamily = opcfamily
JOIN pg_operator opr ON opr.oid = amopopr
WHERE amname = 'spgist'
AND opcname = 'quad_point_ops'
ORDER BY amopstrategy;


   
amopopr | oprcode | amopstrategy
−−−−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−
<<(point,point) | point_left | 1
>>(point,point) | point_right | 5
~=(point,point) | point_eq | 6
<@(point,box) | on_pb | 8
<<|(point,point) | point_below | 10
|>>(point,point) | point_above | 11
<−>(point,point) | point_distance | 15
<^(point,point) | point_below | 29
>^(point,point) | point_above | 30
(9 rows)
               
  
=> SELECT airport_code, airport_name->>'en'
FROM airports_big
WHERE coordinates >^ '(80.3817,73.5167)'::point;
airport_code | ?column?
−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−−−−−−
THU | Thule Air Base
YEU | Eureka Airport
YLT | Alert Airport
YRB | Resolute Bay Airport
LYR | Svalbard Airport, Longyear
NAQ | Qaanaaq Airport
YGZ | Grise Fiord Airport
DKS | Dikson Airport
(8 rows)
=> EXPLAIN (costs off) SELECT airport_code
FROM airports_big
WHERE coordinates >^ '(80.3817,73.5167)'::point;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Bitmap Heap Scan on airports_big
Recheck Cond: (coordinates >^ '(80.3817,73.5167)'::point)
−> Bitmap Index Scan on airports_quad_idx
Index Cond: (coordinates >^ '(80.3817,73.5167)'::point)
(4 rows)
            
            
    

  
          
0
1
2
3
4
5
6
7
8
9
012345678 9


0
1
2
3
4
5
6
7
8
9
012345678 9
              
              
               
           
            
               

5,5
7,7 5,3 3,2
8,9 8,5 6,6 3,3 3,1 0,0 0,4
9,7 1,2




 


   
 
          
             
            
             
     
               
          
       
             
             
               
     
              
              
             
             
             
          
             
       
             
          
              
          
  



  
5,55,5
7,7 3,27,7 3,2
8,9 9,7 8,58,9 9,7 8,5 6,6 5,3 3,36,6 5,3 3,3 3,1 0,0 1,23,1 0,0 1,2 0,40,4
leaf
pages
inner
pages
root
page

              
   
0
1
2
3
4
5
6
7
8
9
012345678 9
           
             
  

   
             
     
              
              
            
              
   
               
             
5,5
7,7 5,3 3,2
8,9 8,5 6,6 3,3 3,1 0,0 0,4
9,7 1,2




 


            
            
          
     
  
  
  

  
0
1
2
3
4
5
6
7
8
9
012345678 9
              
5,5
7,7 5,3 3,2
8,9 8,5 6,6 3,3 3,1 0,0 0,4
9,7 1,2
7,1




 

              
           
           
          
  

   
          
0
1
2
3
4
5
6
7
8
9
012345678 9
0
1
2
3
4
5
6
7
8
9
012345678 9
             
       
5,5
7,7 5,3 3,2
8,9 8,5 6,6 3,3 3,1 1,1 0,4
1,2 0,0
9,7
2,1
7,1




 



  

         
=> SELECT a.amname, p.name, pg_indexam_has_property(a.oid, p.name)
FROM pg_am a, unnest(array[
'can_order', 'can_unique', 'can_multi_col',
'can_exclude', 'can_include'
]) p(name)
WHERE a.amname = 'spgist';
amname | name | pg_indexam_has_property
−−−−−−−−+−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−−−
spgist | can_order | f
spgist | can_unique | f
spgist | can_multi_col | f
spgist | can_exclude | t
spgist | can_include | t
(5 rows)
          
    
       
          
         
=> SELECT p.name, pg_index_has_property('airports_quad_idx', p.name)
FROM unnest(array[
'clusterable', 'index_scan', 'bitmap_scan', 'backward_scan'
]) p(name);
name | pg_index_has_property
−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−
clusterable | f
index_scan | t
bitmap_scan | t
backward_scan | f
(4 rows)
             
            

   
          
=> SELECT p.name,
pg_index_column_has_property('airports_quad_idx', 1, p.name)
FROM unnest(array[
'orderable', 'search_array', 'search_nulls'
]) p(name);
name | pg_index_column_has_property
−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
orderable | f
search_array | f
search_nulls | t
(3 rows)
              
 
                
           
               
             
               
         
=> SELECT p.name,
pg_index_column_has_property('airports_quad_idx', 1, p.name)
FROM unnest(array[
'returnable', 'distance_orderable'
]) p(name);
name | pg_index_column_has_property
−−−−−−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
returnable | t
distance_orderable | t
(2 rows)
               

              
              
         

  
             
  
    
            
             
    
=> CREATE INDEX airports_kd_idx ON airports_big
USING spgist(coordinates kd_point_ops);
            
           
       
             
            
  


    
           
       
          
            

                
            
       

  
    
          
                
  
              

              
           
             
 
              
  
          
V
ADI
IM E ILISA IR LAV
TIN IY
TINA
AL
D
L
SMS
NR


    
              
       
 
          
     
=> SELECT oprname, oprcode::regproc, amopstrategy
FROM pg_am am
JOIN pg_opclass opc ON opcmethod = am.oid
JOIN pg_amop amop ON amopfamily = opcfamily
JOIN pg_operator opr ON opr.oid = amopopr
WHERE amname = 'spgist'
AND opcname = 'text_ops'
ORDER BY amopstrategy;
oprname | oprcode | amopstrategy
−−−−−−−−−+−−−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−
~<~ | text_pattern_lt | 1
~<=~ | text_pattern_le | 2
= | texteq | 3
~>=~ | text_pattern_ge | 4
~>~ | text_pattern_gt | 5
< | text_lt | 11
<= | text_le | 12
>= | text_ge | 14
> | text_gt | 15
^@ | starts_with | 28
(10 rows)
          
             
              
=> CREATE INDEX tickets_spgist_idx ON tickets
USING spgist(passenger_name);
=> EXPLAIN (costs off) SELECT *
FROM tickets
WHERE passenger_name LIKE 'IVAN%';

  
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Bitmap Heap Scan on tickets
Filter: (passenger_name ~~ 'IVAN%'::text)
−> Bitmap Index Scan on tickets_spgist_idx
Index Cond: ((passenger_name ~>=~ 'IVAN'::text) AND
(passenger_name ~<~ 'IVAO'::text))
(5 rows)
              
          
              
  
=> EXPLAIN (costs off) SELECT *
FROM tickets
WHERE passenger_name ^@ 'IVAN';
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Bitmap Heap Scan on tickets
Recheck Cond: (passenger_name ^@ 'IVAN'::text)
−> Bitmap Index Scan on tickets_spgist_idx
Index Cond: (passenger_name ^@ 'IVAN'::text)
(4 rows)
            
              
   

        
SELECT *
FROM names
WHERE name ~>=~ 'VALERIY'
AND name ~<~ 'VLADISLAV';

    
            
           
            
              
             
                 
      
               
          
            
                
            
           
          
          
V
ADI
IM E ILISA IR LAV
TIN IY
TINA
AL
D
L
SMS
NR
  
  

  
             
              
              
  

            
                
              
         
         
            
               
                
              
ADI
IR LAV
MS
AD
IR LAV
I
MS
              
               
             
             

  

    
V
AD
IM E ILISA
TIN IY IR LAV
TINA
AL
D
L
SAI
MS
NR

          
             

=> SELECT p.name,
pg_index_column_has_property('tickets_spgist_idx', 1, p.name)
FROM unnest(array[
'returnable', 'distance_orderable'
]) p(name);
name | pg_index_column_has_property
−−−−−−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
returnable | t
distance_orderable | f
(2 rows)
            
            
    

  
              
      
              
           
              
              
           
             
       
   
             
  
        
         
     
               
           
     
              
        
        
           
          
       
           
  





28
GIN
 
             
          
    
           
            
            
              
           
             
             
             
             
              
             
 
      
         
               
             



  
           
            
          
        
              
         
               
   
              
            
         
           
  
            
            
           
 
    
               
              
        
         
=> CREATE INDEX ts_gin_idx ON ts USING gin(doc_tsv);
            
            
          
    

    
=> SELECT ctid, * FROM ts;
ctid | doc | doc_tsv
−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
(0,1) | Old MacDonald had a farm | 'farm':5 'macdonald':2 'old':1
(0,2) | And on his farm he had some cows | 'cow':8 'farm':4
(0,3) | Here a moo, there a moo | 'moo':3,6
(0,4) | Everywhere a moo moo | 'everywher':1 'moo':3,4
(1,1) | Old MacDonald had a farm | 'farm':5 'macdonald':2 'old':1
(1,2) | And on his farm he had some chicks | 'chick':8 'farm':4
(1,3) | Here a cluck, there a cluck | 'cluck':3,6
(1,4) | Everywhere a cluck cluck | 'cluck':3,4 'everywher':1
(2,1) | Old MacDonald had a farm | 'farm':5 'macdonald':2 'old':1
(2,2) | And on his farm he had some pigs | 'farm':4 'pig':8
(2,3) | Here an oink, there an oink | 'oink':3,6
(2,4) | Everywhere an oink oink | 'everywher':1 'oink':3,4
(12 rows)
metapage
everywher oinkeverywher oink
chick cluck cow everywher farm macdonald moo oink old pig
1,2 1,3
1,4
0,2 0,4
1,4
2,4
0,1
1,1
2,1
0,3
0,4
2,3
2,4
0,1
1,1
2,1
2,2
1,2
0,1 0,2 1,1 1,2 2,1 2,2

  
             
              
               
              
           
          
              
              
    
 
               
            
     
=> CREATE INDEX mail_gin_idx ON mail_messages USING gin(tsv);
             
     
=> SELECT *
FROM gin_metapage_info(get_raw_page('mail_gin_idx',0)) \gx
−[ RECORD 1 ]−−−−+−−−−−−−−−−−
pending_head | 4294967295
pending_tail | 4294967295
tail_free_size | 0
n_pending_pages | 0
n_pending_tuples | 0
n_total_pages | 22957
n_entry_pages | 13522
n_data_pages | 9434
n_entries | 999109
version | 2
               
    

    
=> SELECT flags, count(*)
FROM generate_series(0,22956) AS p,
-- n_total_pages
gin_page_opaque_info(get_raw_page('mail_gin_idx',p))
GROUP BY flags
ORDER BY 2;
flags | count
−−−−−−−−−−−−−−−−−−−−−−−−+−−−−−−−
{meta} | 1
{} | 137
{data} | 1525
{data,leaf,compressed} | 7909
{leaf} | 13385
(5 rows)
              
            
       
           
               
     
=> SELECT left(tids::text,60)||'...' tids
FROM gin_leafpage_items(get_raw_page('mail_gin_idx',24));
tids
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
{"(4771,4)","(4775,2)","(4775,5)","(4777,4)","(4779,1)","(47...
{"(5004,2)","(5011,2)","(5013,1)","(5013,2)","(5013,3)","(50...
{"(5435,6)","(5438,3)","(5439,3)","(5439,4)","(5439,5)","(54...
...
{"(9789,4)","(9791,6)","(9792,4)","(9794,4)","(9794,5)","(97...
{"(9937,4)","(9937,6)","(9938,4)","(9939,1)","(9939,5)","(99...
{"(10116,5)","(10118,1)","(10118,4)","(10119,2)","(10121,2)"...
(27 rows)
            
            
           
      


  
 
          
=> SELECT amprocnum, amproc::regproc
FROM pg_am am
JOIN pg_opclass opc ON opcmethod = am.oid
JOIN pg_amproc amop ON amprocfamily = opcfamily
WHERE amname = 'gin'
AND opcname = 'tsvector_ops'
ORDER BY amprocnum;
amprocnum | amproc
−−−−−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
1 | gin_cmp_tslexeme
2 | pg_catalog.gin_extract_tsvector
3 | pg_catalog.gin_extract_tsquery
4 | pg_catalog.gin_tsquery_consistent
5 | gin_cmp_prefix
6 | gin_tsquery_triconsistent
(6 rows)
            
           
         
             
           
         
*

      
            
            
             
            
             
            
               
            
            



    
                
              

         
            
             
            
                
            
               

           
            


            
          
            

            
               
              
              
           
              
              
      
  
  
  

  
everywher oinkeverywher oink
chick cluck cow everywher farm macdonald moo oink old pig
1,2 1,3
1,4
0,2 0,4
1,4
2,4
0,1
1,1
2,1
0,3
0,4
2,3
2,4
0,1
1,1
2,1
2,2
1,2
0,1 0,2 1,1 1,2 2,1 2,2
           
             
                 

          

   
 33
 33
 3 3
 3 3 3
             
             
  

    
         
*
    
           
            
           
          
    
   
             
              
      
            
            
              
               
           
          
            
              
             
            
               
             
           
           
             
              
             
   
  
  

  
           
              
          
             
            
          
              
            
      
everywher oinkeverywher oink
chick cluck cow everywher farm macdonald moo oink old pig
1,2 1,3
1,4
0,2 0,4
1,4
2,4
0,1
1,1
2,1
0,3
0,4
2,3
2,4
0,1
1,1
2,1
2,2
1,2
0,1 0,2 1,1 1,2 2,1 2,2
             
 

    
 33 3
 3
 3

    
                
            
              
      
           
          
=> SELECT word, ndoc
FROM ts_stat('SELECT tsv FROM mail_messages')
WHERE word IN ('wrote', 'tattoo');
word | ndoc
−−−−−−−−+−−−−−−−−
wrote | 231173
tattoo | 2
(2 rows)
          
=> \timing on
=> SELECT count(*) FROM mail_messages
WHERE tsv @@ to_tsquery('wrote & tattoo');
count
−−−−−−−
1
(1 row)
Time: 0,631 ms
              
=> SELECT count(*) FROM mail_messages
WHERE tsv @@ to_tsquery('tattoo');
count
−−−−−−−
2
(1 row)
Time: 2,227 ms
             

=> SELECT count(*) FROM mail_messages
WHERE tsv @@ to_tsquery('wrote');

  
count
−−−−−−−−
231173
(1 row)
Time: 343,556 ms
=> \timing off

           
                 
             
               
 
             
              
 
            
              
         
             
               
            
          
            
               
         
     on     
            
            
  
  
  

    
                
          4MB
       
everywher oinkeverywher oink
chick cluck cow everywher farm macdonald moo oink old pig
1,2 1,3
1,4
4,1
0,2 0,1
1,1
2,1
0,3
0,4
4,1
2,3
2,4
4,1
0,1
1,1
2,1
2,2
1,2
0,1 0,2 1,1 1,2 2,1 2,2
2,4
0,4 1,4 2,4 4,1
             
              
            
            
             
   
            
              
         64MB 
              
             
  
  

  
           
                
             
           
   
             
                
    
              
               
               
              
              
               

             
               
=> EXPLAIN SELECT *FROM mail_messages
WHERE tsv @@ to_tsquery('hacker')
LIMIT 1000;
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Limit (cost=481.41..1964.22 rows=1000 width=1258)
−> Bitmap Heap Scan on mail_messages
(cost=481.41..74939.28 rows=50214 width=1258)
Recheck Cond: (tsv @@ to_tsquery('hacker'::text))
−> Bitmap Index Scan on mail_gin_idx
(cost=0.00..468.85 rows=50214 width=0)
Index Cond: (tsv @@ to_tsquery('hacker'::text))
(7 rows)
            
           0
             

    
            
     
=> SET gin_fuzzy_search_limit = 1000;
=> SELECT count(*)
FROM mail_messages
WHERE tsv @@ to_tsquery('hacker');
count
−−−−−−−
727
(1 row)
=> SELECT count(*)
FROM mail_messages
WHERE tsv @@ to_tsquery('hacker');
count
−−−−−−−
791
(1 row)
=> RESET gin_fuzzy_search_limit;
               
              
             
     

                
    
  
=> SELECT a.amname, p.name, pg_indexam_has_property(a.oid, p.name)
FROM pg_am a, unnest(array[
'can_order', 'can_unique', 'can_multi_col',
'can_exclude', 'can_include'
]) p(name)
WHERE a.amname = 'gin';
  

  
amname | name | pg_indexam_has_property
−−−−−−−−+−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−−−
gin | can_order | f
gin | can_unique | f
gin | can_multi_col | t
gin | can_exclude | f
gin | can_include | f
(5 rows)
      
            
          
           
  
           

           
               
             
  
 
=> SELECT p.name, pg_index_has_property('mail_gin_idx', p.name)
FROM unnest(array[
'clusterable', 'index_scan', 'bitmap_scan', 'backward_scan'
]) p(name);
name | pg_index_has_property
−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−
clusterable | f
index_scan | f
bitmap_scan | t
backward_scan | f
(4 rows)
            

              
            

    
            
   
 
=> SELECT p.name,
pg_index_column_has_property('mail_gin_idx', 1, p.name)
FROM unnest(array[
'orderable', 'search_array', 'search_nulls',
'returnable', 'distance_orderable'
]) p(name);
name | pg_index_column_has_property
−−−−−−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
orderable | f
search_array | f
search_nulls | f
returnable | f
distance_orderable | f
(5 rows)
           
               
             
  
    
              
           
               
          
             
           
          
          
             

  
             
          
              
            
           
          
            
           
          
            
              
          
  
 
           
         
              
  
          
           
            
           
            
        
=> CREATE EXTENSION pg_trgm;
=> SELECT unnest(show_trgm('macdonald')),
unnest(show_trgm('McDonald'));





 
unnest | unnest
−−−−−−−−+−−−−−−−−
m | m
ma | mc
acd | ald
ald | cdo
cdo | don
don | ld
ld | mcd
mac | nal
nal | ona
ona |
(10 rows)
            

=> SELECT amopopr::regoperator, oprcode::regproc
FROM pg_am am
JOIN pg_opclass opc ON opcmethod = am.oid
JOIN pg_amop amop ON amopfamily = opcfamily
JOIN pg_operator opr ON opr.oid = amopopr
WHERE amname = 'gin'
AND opcname = 'gin_trgm_ops'
ORDER BY amopstrategy;
amopopr | oprcode
−−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
%(text,text) | similarity_op
~~(text,text) | textlike
~~*(text,text) | texticlike
~(text,text) | textregexeq
~*(text,text) | texticregexeq
%>(text,text) | word_similarity_commutator_op
%>>(text,text) | strict_word_similarity_commutator_op
=(text,text) | texteq
(8 rows)
regular expressions
LIKE and ILIKE
           
              
            
            
           
       

  
           
           
     
              
  
              
              
 
=> SELECT amopopr::regoperator, oprcode::regproc, amopstrategy
FROM pg_am am
JOIN pg_opclass opc ON opcmethod = am.oid
JOIN pg_amop amop ON amopfamily = opcfamily
JOIN pg_operator opr ON opr.oid = amopopr
WHERE amname = 'gin'
AND opcname = 'array_ops'
ORDER BY amopstrategy;
amopopr | oprcode | amopstrategy
−−−−−−−−−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−
&&(anyarray,anyarray) | arrayoverlap | 1
@>(anyarray,anyarray) | arraycontains | 2
<@(anyarray,anyarray) | arraycontained | 3
=(anyarray,anyarray) | array_eq | 4
(4 rows)
               
              
           

=> CREATE TABLE routes_tbl AS SELECT *FROM routes;
SELECT 710
=> CREATE INDEX ON routes_tbl USING gin(days_of_week);
             
           
     

  
=> SET enable_seqscan = off;
=> EXPLAIN (costs off) SELECT *FROM routes_tbl
WHERE days_of_week = ARRAY[2,4,7];
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Bitmap Heap Scan on routes_tbl
Recheck Cond: (days_of_week = '{2,4,7}'::integer[])
−> Bitmap Index Scan on routes_tbl_days_of_week_idx
Index Cond: (days_of_week = '{2,4,7}'::integer[])
(4 rows)
        
=> SELECT flight_no, departure_airport, arrival_airport,
days_of_week
FROM routes_tbl
WHERE days_of_week = ARRAY[2,4,7];
flight_no | departure_airport | arrival_airport | days_of_week
−−−−−−−−−−−+−−−−−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−
PG0023 | OSW | KRO | {2,4,7}
PG0123 | NBC | ROV | {2,4,7}
PG0155 | ARH | TJM | {2,4,7}
PG0260 | STW | CEK | {2,4,7}
PG0261 | SVO | GDZ | {2,4,7}
PG0310 | UUD | NYM | {2,4,7}
PG0370 | DME | KRO | {2,4,7}
PG0371 | KRO | DME | {2,4,7}
PG0448 | VKO | STW | {2,4,7}
PG0482 | DME | KEJ | {2,4,7}
PG0651 | UIK | KHV | {2,4,7}
(11 rows)
           
    
             
            
              
            
            
          
             
       
  

  
=> EXPLAIN (analyze, costs off, timing off, summary off)
SELECT *FROM routes_tbl
WHERE days_of_week = ARRAY[2,4,7];
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Bitmap Heap Scan on routes_tbl (actual rows=11 loops=1)
Recheck Cond: (days_of_week = '{2,4,7}'::integer[])
Rows Removed by Index Recheck: 482
Heap Blocks: exact=16
−> Bitmap Index Scan on routes_tbl_days_of_week_idx (actual ro...
Index Cond: (days_of_week = '{2,4,7}'::integer[])
(6 rows)
             
            
            
      
=> CREATE INDEX ON routes_tbl USING gin(days_of_week, departure_city);
ERROR: data type text has no default operator class for access
method "gin"
HINT: You must specify an operator class for the index or define a
default operator class for the data type.
             
         
    
=> CREATE EXTENSION btree_gin;
=> CREATE INDEX ON routes_tbl USING gin(days_of_week,departure_city);
=> EXPLAIN (costs off)
SELECT *FROM routes_tbl
WHERE days_of_week = ARRAY[2,4,7]
AND departure_city = 'Moscow';
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Bitmap Heap Scan on routes_tbl
Recheck Cond: ((days_of_week = '{2,4,7}'::integer[]) AND
(departure_city = 'Moscow'::text))
−> Bitmap Index Scan on routes_tbl_days_of_week_departure_city...
Index Cond: ((days_of_week = '{2,4,7}'::integer[]) AND
(departure_city = 'Moscow'::text))
(6 rows)

  
=> RESET enable_seqscan;
             
              
           
              
     
  
           
              
            

=> SELECT opcname
FROM pg_am am
JOIN pg_opclass opc ON opcmethod = am.oid
WHERE amname = 'gin'
AND opcintype = 'jsonb'::regtype;
opcname
−−−−−−−−−−−−−−−−
jsonb_ops
jsonb_path_ops
(2 rows)
  
             
           
              
       

  

  
=> SELECT amopopr::regoperator, oprcode::regproc, amopstrategy
FROM pg_am am
JOIN pg_opclass opc ON opcmethod = am.oid
JOIN pg_amop amop ON amopfamily = opcfamily
JOIN pg_operator opr ON opr.oid = amopopr
WHERE amname = 'gin'
AND opcname = 'jsonb_ops'
ORDER BY amopstrategy;
amopopr | oprcode | amopstrategy
−−−−−−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−
@>(jsonb,jsonb) | jsonb_contains | 7
?(jsonb,text) | jsonb_exists | 9
?|(jsonb,text[]) | jsonb_exists_any | 10
?&(jsonb,text[]) | jsonb_exists_all | 11
@?(jsonb,jsonpath) | jsonb_path_exists_opr | 15
@@(jsonb,jsonpath) | jsonb_path_match_opr | 16
(6 rows)
           
=> CREATE TABLE routes_jsonb AS
SELECT to_jsonb(t) route
FROM (
SELECT departure_airport_name, arrival_airport_name, days_of_week
FROM routes
ORDER BY flight_no
LIMIT 4
) t;
=> SELECT ctid, jsonb_pretty(route) FROM routes_jsonb;
ctid | jsonb_pretty
−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
(0,1) | { +
| "days_of_week": [ +
| 6 +
| ], +
| "arrival_airport_name": "Surgut Airport", +
| "departure_airport_name": "Ust−Ilimsk Airport" +
| }
(0,2) | { +
| "days_of_week": [ +
| 7 +
| ], +
| "arrival_airport_name": "Ust−Ilimsk Airport", +
| "departure_airport_name": "Surgut Airport" +
| }

  
(0,3) | { +
| "days_of_week": [ +
| 2, +
| 6 +
| ], +
| "arrival_airport_name": "Sochi International Airport", +
| "departure_airport_name": "Ivanovo South Airport" +
| }
(0,4) | { +
| "days_of_week": [ +
| 3, +
| 7 +
| ], +
| "arrival_airport_name": "Ivanovo South Airport", +
| "departure_airport_name": "Sochi International Airport"+
| }
(4 rows)
=> CREATE INDEX ON routes_jsonb USING gin(route);
       
arrival_airport_name Ivanovo-Yuzhnyarrival_airport_name Ivanovo-Yuzhny
2
3
6
7
arrival_airport_name
days_of_week
departure_airport_name
Ivanovo-Yuzhny
Sochi
Surgut
Ust-Ilimsk
0,3 0,4 0,1
0,3
0,2
0,4
0,1
0,2
0,3
0,4
0,1
0,2
0,3
0,4
0,1
0,2
0,3
0,4
0,3
0,4
0,3
0,4
0,1
0,2
0,1
0,2
          
           


  
            
            
             
          
             
              
   
  
       
=> SELECT amopopr::regoperator, oprcode::regproc, amopstrategy
FROM pg_am am
JOIN pg_opclass opc ON opcmethod = am.oid
JOIN pg_amop amop ON amopfamily = opcfamily
JOIN pg_operator opr ON opr.oid = amopopr
WHERE amname = 'gin'
AND opcname = 'jsonb_path_ops'
ORDER BY amopstrategy;
amopopr | oprcode | amopstrategy
−−−−−−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−
@>(jsonb,jsonb) | jsonb_contains | 7
@?(jsonb,jsonpath) | jsonb_path_exists_opr | 15
@@(jsonb,jsonpath) | jsonb_path_match_opr | 16
(3 rows)
               
             
              
         
              
  
           
  
  
  

  
=> CREATE INDEX ON routes_jsonb USING gin(route jsonb_path_ops);
        
HASH( ... ) HASH( ... )HASH( ... ) HASH( ... )
HASH( departure_airport_name, Ivanovo-Yuzhny )
HASH( departure_airport_name, Sochi )
HASH( departure_airport_name, Ust-Ilimsk )
HASH( departure_airport_name, Surgut )
HASH( days_of_week, 3 )
HASH( arrival_airport_name, Surgut )
HASH( arrival_airport_name, Sochi )
HASH( arrival_airport_name, Ust-Ilimsk )
HASH( days_of_week, 7 )
HASH( arrival_airport_name, Ivanovo-Yuzhny )
HASH( days_of_week, 6 )
HASH( days_of_week, 2 )
0,3 0,4 0,1 0,2 0,4 0,1 0,3 0,2 0,2
0,4
0,4 0,1
0,3
0,3
          
          
            
    
          
           
              
            
  
  
  

  
    
           
           
             
         

         
           

           
      
          
           
 

29
BRIN
 
            
           
             
  
             
            
              
            
        
               
     128  
            
               
                

             
           
             
            



  
              
       
               
               
         
 
              
          
           
              
             
  
    
CREATE TABLE flights_bi(
airport_code char(3),
airport_coord point,
-- airport coordinates
airport_utc_offset interval,
-- timezone
flight_no char(6),
flight_type text,
-- departure or arrival
scheduled_time timestamptz,
actual_time timestamptz,
aircraft_code char(3),
seat_no varchar(4),
fare_conditions varchar(10),
-- travel class
passenger_id varchar(20),
passenger_name text
);
           
              
               
            


 
             
   
postgres$ pg_restore -d demo -c flights_bi.dump
=> ANALYZE flights_bi;
=> SELECT count(*) FROM flights_bi;
count
−−−−−−−−−−
30517076
(1 row)
=> SELECT pg_size_pretty(pg_total_relation_size('flights_bi'));
pg_size_pretty
−−−−−−−−−−−−−−−−
4129 MB
(1 row)
              
         
=> CREATE INDEX ON flights_bi USING brin(scheduled_time);
=> SELECT pg_size_pretty(pg_total_relation_size(
'flights_bi_scheduled_time_idx'
));
pg_size_pretty
−−−−−−−−−−−−−−−−
184 kB
(1 row)
        
           
              
      
=> CREATE INDEX flights_bi_btree_idx ON flights_bi(scheduled_time);
=> SELECT pg_size_pretty(pg_total_relation_size(
'flights_bi_btree_idx'
));


  
pg_size_pretty
−−−−−−−−−−−−−−−−
210 MB
(1 row)
=> DROP INDEX flights_bi_btree_idx;
  
              

          
           
           
             
           
            
metapage
revmap
1 .. 10 11 .. 20 21 .. 301 .. 10 11 .. 20 21 .. 30 71 .. 80 31 .. 40 41 .. 5071 .. 80 31 .. 40 41 .. 50 51 .. 60 61 .. 7051 .. 60 61 .. 70
                 
              
            
      

  
            
              
 
=> SELECT pagesperrange, lastrevmappage
FROM brin_metapage_info(get_raw_page(
'flights_bi_scheduled_time_idx', 0
));
pagesperrange | lastrevmappage
−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−
128 | 4
(1 row)
               
         
=> SELECT *
FROM brin_revmap_data(get_raw_page(
'flights_bi_scheduled_time_idx', 1
));
pages
−−−−−−−−−−
(6,197)
(6,198)
(6,199)
...
(6,195)
(6,196)
(1360 rows)
              
       
=> SELECT itemoffset, blknum, value
FROM brin_page_items(
get_raw_page('flights_bi_scheduled_time_idx', 6),
'flights_bi_scheduled_time_idx'
)
ORDER BY blknum
LIMIT 3\gx

  
−[ RECORD 1 ]−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
itemoffset | 197
blknum | 0
value | {2016−08−15 02:45:00+03 .. 2016−08−15 16:20:00+03}
−[ RECORD 2 ]−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
itemoffset | 198
blknum | 128
value | {2016−08−15 05:50:00+03 .. 2016−08−15 18:55:00+03}
−[ RECORD 3 ]−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
itemoffset | 199
blknum | 256
value | {2016−08−15 07:15:00+03 .. 2016−08−15 18:50:00+03}
 
            
              
                
            
           
        
   
                
           
   
   
 
             
           
  
  

   
          
     
          
             
          
               
             
             
              
               
     
metapage
revmap
1 .. 10 11 .. 20 21 .. 301 .. 10 11 .. 20 21 .. 30 71 .. 80 31 .. 42 41 .. 5071 .. 80 31 .. 42 41 .. 50 51 .. 60 61 .. 7051 .. 60 61 .. 70
              

 
            
             
            
       off     
             
              


  
             
         
         
         
     
           
              
             
           
           
          
            
            
            
           
          
          
              
                 
           
  
           
          
    
=> SELECT opcname
FROM pg_am am
JOIN pg_opclass opc ON opcmethod = am.oid
WHERE amname = 'brin'
AND opcname LIKE '%minmax_ops'
ORDER BY opcname;
  


  
opcname
−−−−−−−−−−−−−−−−−−−−−−−−
bit_minmax_ops
bpchar_minmax_ops
bytea_minmax_ops
char_minmax_ops
...
timestamptz_minmax_ops
timetz_minmax_ops
uuid_minmax_ops
varbit_minmax_ops
(26 rows)
        
=> SELECT amprocnum, amproc::regproc
FROM pg_am am
JOIN pg_opclass opc ON opcmethod = am.oid
JOIN pg_amproc amop ON amprocfamily = opcfamily
WHERE amname = 'brin'
AND opcname = 'numeric_minmax_ops'
ORDER BY amprocnum;
amprocnum | amproc
−−−−−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−−
1 | brin_minmax_opcinfo
2 | brin_minmax_add_value
3 | brin_minmax_consistent
4 | brin_minmax_union
(4 rows)
            
           
  
           
  
=> SELECT amopopr::regoperator, oprcode::regproc, amopstrategy
FROM pg_am am
JOIN pg_opclass opc ON opcmethod = am.oid
JOIN pg_amop amop ON amopfamily = opcfamily
JOIN pg_operator opr ON opr.oid = amopopr
WHERE amname = 'brin'
AND opcname = 'numeric_minmax_ops'
ORDER BY amopstrategy;

  
amopopr | oprcode | amopstrategy
−−−−−−−−−−−−−−−−−−−−−+−−−−−−−−−−−−+−−−−−−−−−−−−−−
<(numeric,numeric) | numeric_lt | 1
<=(numeric,numeric) | numeric_le | 2
=(numeric,numeric) | numeric_eq | 3
>=(numeric,numeric) | numeric_ge | 4
>(numeric,numeric) | numeric_gt | 5
(5 rows)
    
             
            
     
      
=> SELECT attname, correlation, n_distinct
FROM pg_stats
WHERE tablename = 'flights_bi'
ORDER BY correlation DESC NULLS LAST;
attname | correlation | n_distinct
−−−−−−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−
scheduled_time | 0.9999949 | 25926
actual_time | 0.9999948 | 34469
fare_conditions | 0.7976897 | 3
flight_type | 0.4981733 | 2
airport_utc_offset | 0.4440067 | 11
aircraft_code | 0.19249801 | 8
airport_code | 0.061483838 | 104
seat_no | 0.0024594965 | 461
flight_no | 0.0020146023 | 710
passenger_id | −0.00046121294 | 2.610987e+06
passenger_name | −0.012388787 | 8618
airport_coord | | 0
(12 rows)
              
              
                
   

  
       
       
             
      
    
             
   
             
              
       
               
            
              
   
=> CREATE FUNCTION tid2page(t tid) RETURNS integer
LANGUAGE sql
RETURN (t::text::point)[0]::integer;
          
=> SELECT min(numblk), round(avg(numblk)) avg, max(numblk)
FROM (
SELECT count(distinct tid2page(ctid)) numblk
FROM flights_bi
GROUP BY scheduled_time::date
) t;
min | avg | max
−−−−−−+−−−−−−+−−−−−−
1192 | 1447 | 1512
(1 row)
             
               
              
              

  
              
       
              
        
=> SET max_parallel_workers_per_gather = 0;
=> \set d '2016-08-15 02:45:00+03'
=> EXPLAIN (analyze, buffers, costs off, timing off, summary off)
SELECT *
FROM flights_bi
WHERE scheduled_time >= :'d'::timestamptz
AND scheduled_time < :'d'::timestamptz + interval '1 day';
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Bitmap Heap Scan on flights_bi (actual rows=81964 loops=1)
Recheck Cond: ((scheduled_time >= '2016−08−15 02:45:00+03'::ti...
Rows Removed by Index Recheck: 11606
Heap Blocks: lossy=1536
Buffers: shared hit=1561
−> Bitmap Index Scan on flights_bi_scheduled_time_idx
(actual rows=15360 loops=1)
Index Cond: ((scheduled_time >= '2016−08−15 02:45:00+03'::...
Buffers: shared hit=25
Planning:
Buffers: shared hit=1
(11 rows)
            
              
              
            
              
             
 
        
    
      
          
            
           

  
               
  
               
            
            
              
       
=> DO $$
DECLARE
plan jsonb;
BEGIN
EXECUTE
'EXPLAIN (analyze, buffers, timing off, costs off, format json)
SELECT * FROM flights_bi
WHERE scheduled_time >= $1
AND scheduled_time < $1 + interval ''1 day'''
USING '2016-08-15 02:45:00+03'::timestamptz
INTO plan;
RAISE NOTICE 'shared hit=%, read=%',
plan -> 0 -> 'Plan' ->> 'Shared Hit Blocks',
plan -> 0 -> 'Plan' ->> 'Shared Read Blocks';
END;
$$;
NOTICE: shared hit=1561, read=0
DO
            
             
               
              
           
         
              
   
             
  
             
         
   

  
0,990 0,992 0,994 0,996 0,998 1,000
efciency
factor
32 pages/range,
529 kB
128 pages/range,
184 kB
512 pages/range,
72 kB
              
            

          
  
=> SELECT a.amname, p.name, pg_indexam_has_property(a.oid, p.name)
FROM pg_am a, unnest(array[
'can_order', 'can_unique', 'can_multi_col',
'can_exclude', 'can_include'
]) p(name)
WHERE a.amname = 'brin';
amname | name | pg_indexam_has_property
−−−−−−−−+−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−−−
brin | can_order | f
brin | can_unique | f
brin | can_multi_col | t
brin | can_exclude | f
brin | can_include | f
(5 rows)
         
          
             
   

  
           
              
              
     
           
            
=> CREATE INDEX ON flights_bi USING brin(airport_utc_offset);
=> EXPLAIN (analyze, costs off, timing off, summary off)
SELECT *
FROM flights_bi
WHERE scheduled_time >= :'d'::timestamptz
AND scheduled_time < :'d'::timestamptz + interval '1 day'
AND airport_utc_offset = '08:00:00';
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Bitmap Heap Scan on flights_bi (actual rows=1658 loops=1)
Recheck Cond: ((scheduled_time >= '2016−08−15 02:45:00+03'::ti...
Rows Removed by Index Recheck: 14077
Heap Blocks: lossy=256
−> BitmapAnd (actual rows=0 loops=1)
−> Bitmap Index Scan on flights_bi_scheduled_time_idx (act...
Index Cond: ((scheduled_time >= '2016−08−15 02:45:00+0...
−> Bitmap Index Scan on flights_bi_airport_utc_offset_idx ...
Index Cond: (airport_utc_offset = '08:00:00'::interval)
(9 rows)
 
=> SELECT p.name, pg_index_has_property(
'flights_bi_scheduled_time_idx', p.name
)
FROM unnest(array[
'clusterable', 'index_scan', 'bitmap_scan', 'backward_scan'
]) p(name);
name | pg_index_has_property
−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−
clusterable | f
index_scan | f
bitmap_scan | t
backward_scan | f
(4 rows)

  
        
            
              
           
            
             
   
 
=> SELECT p.name, pg_index_column_has_property(
'flights_bi_scheduled_time_idx', 1, p.name
)
FROM unnest(array[
'orderable', 'distance_orderable', 'returnable',
'search_array', 'search_nulls'
]) p(name);
name | pg_index_column_has_property
−−−−−−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
orderable | f
distance_orderable | f
returnable | f
search_array | f
search_nulls | t
(5 rows)
           
     
=> SELECT hasnulls, allnulls, value
FROM brin_page_items(
get_raw_page('flights_bi_airport_utc_offset_idx', 6),
'flights_bi_airport_utc_offset_idx'
)
WHERE itemoffset= 1;
hasnulls | allnulls | value
−−−−−−−−−−+−−−−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−−
f | f | {03:00:00 .. 03:00:00}
(1 row)

  
   
            
              
                
             
 
             
              
            
             
        
           
            
=> WITH tAS (
SELECT ctid
FROM flights_bi TABLESAMPLE BERNOULLI(0.1) REPEATABLE(0)
)
DELETE FROM flights_bi
WHERE ctid IN (SELECT ctid FROM t);
DELETE 30180
=> VACUUM flights_bi;
               
     
=> INSERT INTO flights_bi
SELECT airport_code, airport_coord, airport_utc_offset,
flight_no, flight_type, scheduled_time + interval '1 day',
actual_time + interval '1 day', aircraft_code, seat_no,
fare_conditions, passenger_id, passenger_name
FROM flights_bi
WHERE date_trunc('day', scheduled_time) = '2017-08-15'
AND airport_utc_offset = '03:00:00';
INSERT 0 40532

  
              
             
         
               
 
=> SELECT value
FROM brin_page_items(
get_raw_page('flights_bi_scheduled_time_idx', 6),
'flights_bi_scheduled_time_idx'
)
WHERE blknum = 0;
value
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
{2016−08−15 02:45:00+03 .. 2017−08−16 09:35:00+03}
(1 row)
              
       
0 0,1 0,2 0,3 0,4 0,5 0,6 0,7 0,8 0,9 1
efciency
factor
128 pages/range,
248 kB
           
           
              
            
      
=> SELECT opcname
FROM pg_am am
JOIN pg_opclass opc ON opcmethod = am.oid
WHERE amname = 'brin'
AND opcname LIKE '%minmax_multi_ops'
ORDER BY opcname;


  
opcname
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
date_minmax_multi_ops
float4_minmax_multi_ops
float8_minmax_multi_ops
inet_minmax_multi_ops
...
time_minmax_multi_ops
timestamp_minmax_multi_ops
timestamptz_minmax_multi_ops
timetz_minmax_multi_ops
uuid_minmax_multi_ops
(19 rows)
           
            
         
=> SELECT amprocnum, amproc::regproc
FROM pg_am am
JOIN pg_opclass opc ON opcmethod = am.oid
JOIN pg_amproc amop ON amprocfamily = opcfamily
WHERE amname = 'brin'
AND opcname = 'numeric_minmax_multi_ops'
ORDER BY amprocnum;
amprocnum | amproc
−−−−−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
1 | brin_minmax_multi_opcinfo
2 | brin_minmax_multi_add_value
3 | brin_minmax_multi_consistent
4 | brin_minmax_multi_union
5 | brin_minmax_multi_options
11 | brin_minmax_multi_distance_numeric
(6 rows)
             

     32    
          
           
           
  

  
            
       
=> DROP INDEX flights_bi_scheduled_time_idx;
=> CREATE INDEX ON flights_bi USING brin(
scheduled_time timestamptz_minmax_multi_ops(
values_per_range = 16
)
);
              
          
0,990 0,992 0,994 0,996 0,998 1,000
efciency
factor
minmax-multi
656 kB
minmax
184 kB
  
           
             
          
          
           
   
        
=> SELECT opcname
FROM pg_am am
JOIN pg_opclass opc ON opcmethod = am.oid
WHERE amname = 'brin'
AND opcname LIKE '%inclusion_ops'
ORDER BY opcname;

  
opcname
−−−−−−−−−−−−−−−−−−−−−
box_inclusion_ops
inet_inclusion_ops
range_inclusion_ops
(3 rows)
           
        
=> SELECT amprocnum, amproc::regproc
FROM pg_am am
JOIN pg_opclass opc ON opcmethod = am.oid
JOIN pg_amproc amop ON amprocfamily = opcfamily
WHERE amname = 'brin'
AND opcname = 'box_inclusion_ops'
ORDER BY amprocnum;
amprocnum | amproc
−−−−−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−−−−−
1 | brin_inclusion_opcinfo
2 | brin_inclusion_add_value
3 | brin_inclusion_consistent
4 | brin_inclusion_union
11 | bound_box
13 | box_contain
(6 rows)
            
               
     
             
              
            

       
               
        
  
  

  
            
                
        
=> CREATE INDEX ON flights_bi USING brin(box(airport_coord))
WITH (pages_per_range = 8);
=> SELECT pg_size_pretty(pg_total_relation_size(
'flights_bi_box_idx'
));
pg_size_pretty
−−−−−−−−−−−−−−−−
3816 kB
(1 row)
            
   
            
             
=> SELECT airport_code, airport_name
FROM airports
WHERE box(coordinates) <@ box '135,45,140,50';
airport_code | airport_name
−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−−−
KHV | Khabarovsk−Novy Airport
(1 row)
              
  
=> EXPLAIN (costs off)
SELECT *
FROM flights_bi
WHERE box(airport_coord) <@ box '135,45,140,50';
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Seq Scan on flights_bi
Filter: (box(airport_coord) <@ '(140,50),(135,45)'::box)
(2 rows)
=> SET enable_seqscan = off;

  
=> EXPLAIN (analyze, costs off, timing off, summary off)
SELECT *
FROM flights_bi
WHERE box(airport_coord) <@ box '135,45,140,50';
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Bitmap Heap Scan on flights_bi (actual rows=511414 loops=1)
Recheck Cond: (box(airport_coord) <@ '(140,50),(135,45)'::box)
Rows Removed by Index Recheck: 630756
Heap Blocks: lossy=19656
−> Bitmap Index Scan on flights_bi_box_idx (actual rows=196560...
Index Cond: (box(airport_coord) <@ '(140,50),(135,45)'::box)
(6 rows)
=> RESET enable_seqscan;
   
             
            
             
          
         
=> SELECT opcname
FROM pg_am am
JOIN pg_opclass opc ON opcmethod = am.oid
WHERE amname = 'brin'
AND opcname LIKE '%bloom_ops'
ORDER BY opcname;
opcname
−−−−−−−−−−−−−−−−−−−−−−−
bpchar_bloom_ops
bytea_bloom_ops
char_bloom_ops
...
timestamptz_bloom_ops
timetz_bloom_ops
uuid_bloom_ops
(24 rows)


  
            
              
            
             
             
             
             
                 
              
                  
       
               
            
     
             
                
               
             
             
       
            
           
 
              
           

−0.1             
             
            
           


  
0.01      
           
            
              
             
   
        
=> SELECT amprocnum, amproc::regproc
FROM pg_am am
JOIN pg_opclass opc ON opcmethod = am.oid
JOIN pg_amproc amop ON amprocfamily = opcfamily
WHERE amname = 'brin'
AND opcname = 'numeric_bloom_ops'
ORDER BY amprocnum;
amprocnum | amproc
−−−−−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−
1 | brin_bloom_opcinfo
2 | brin_bloom_add_value
3 | brin_bloom_consistent
4 | brin_bloom_union
5 | brin_bloom_options
11 | hash_numeric
(6 rows)
             
=> SELECT amopopr::regoperator, oprcode::regproc, amopstrategy
FROM pg_am am
JOIN pg_opclass opc ON opcmethod = am.oid
JOIN pg_amop amop ON amopfamily = opcfamily
JOIN pg_operator opr ON opr.oid = amopopr
WHERE amname = 'brin'
AND opcname = 'numeric_bloom_ops'
ORDER BY amopstrategy;
amopopr | oprcode | amopstrategy
−−−−−−−−−−−−−−−−−−−−+−−−−−−−−−−−−+−−−−−−−−−−−−−−
=(numeric,numeric) | numeric_eq | 1
(1 row)
            
             

  
             
           

=> SELECT max(nd)
FROM (
SELECT count(distinct flight_no) nd
FROM flights_bi
GROUP BY tid2page(ctid) / 8
) t;
max
−−−−−
22
(1 row)
              
       
          
=> CREATE INDEX ON flights_bi USING brin(
flight_no bpchar_bloom_ops(
n_distinct_per_range = 22)
)
WITH (pages_per_range = 8);
=> EXPLAIN (analyze, costs off, timing off, summary off)
SELECT *
FROM flights_bi
WHERE flight_no = 'PG0001';
QUERY PLAN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Bitmap Heap Scan on flights_bi (actual rows=5192 loops=1)
Recheck Cond: (flight_no = 'PG0001'::bpchar)
Rows Removed by Index Recheck: 122894
Heap Blocks: lossy=2168
−> Bitmap Index Scan on flights_bi_flight_no_idx (actual rows=...
Index Cond: (flight_no = 'PG0001'::bpchar)
(6 rows)
=> RESET max_parallel_workers_per_gather;
            
               
   

  
0,70 0,75 0,80 0,85 0,90 0,95 1,00
efciency
factor
2 pages/range,
14,8 MB
4 pages/range,
7,4 Mb
8 pages/range,
3,7 MB

Conclusion
               
           
      
             
            
              
            
         
                 
             
       
               
            
   
              
          
              
    
 

Index
A
    
 
 
  
 
 
 
  
  
 
 
    

    
    
    
    
    
   

    
 
   
      
  
  
  
  
 
 
  
  


 
  
 

 
 
  




 
 
 
 











 
 


B
 
    
  
 
   
   
 
  
 
 
 
 
  
      
     
 
 
     
  
  
 
   
  
 
  
    
 
 
 
     
    
 
 
 
  
      
  
 
 
  
    
   
C
   
 
   
  
 
 


   
 
  
 
 
     
 
   
   
 
   
 
 
 
 
  
   
     

   


 
    
 
    
  
  
  
 
     
  
D
 
 
   
   
 
 
 
 
  
 
  
 
 
 
    
   
 
E
 
 
 
  
 
 
  
    
    
   
  
F
 
  
 
   
     

  
  
 
 
    
 
     
 
   
    
 
    
 
  
 
   
  
  
  
 
 
 
 


G
    
  
 
 
   
  
 
  
  
    

 
 
 
 
  
    
 
  
 
  
H
    
  
 
 
    
      

 
   


  
  
 
    
    
 
     
   
  
I


 
  
  
     
 
   
    
  
   
    
    
 
 
   
 
     

  
 
   
     
   
      

  
 


  
  
 
    
J

    
    
     

  
  
 
  
  
    
   
   
 
 
  
 
K
  
L
   
 
  
  
 
 
   
 
 
 
   
     
  
  
 
 
  
 
 
 
 
  
 
  
    
 
M
 
  
 

    
    
    
    

   
   

  
 
 
 




 
 


 
  
  
  
  
   
   
 
 
 
 
 
 
  
   
N
 
    
 
     
    
     
    
    
   

      
 
O
 
 
    
   
  
  
  
P
  
 
  
  
  
 
    

      
     
 
    
    
    
 
  
   
    
   
 

  
  
 
 
  
  
   
  
 


 
 
 
 
 


 
  
 
 
   
  
 
 
   
    
 
   
 
  
   
 
 
     
  
  
 
 
  
  
     
      
Q
 
R
   
 
     
    
  
    
   
   
 
     
 
 
 
    
    
   
  
  
   
 
 
  
 
S
 

     
  
    
  
     

    
   
  


  
  
  
 
 
 
 
  
  
 
     
    
    
   
 
 
 
  
  
 
   
 
  
    
      
 
 
 
 
 
  
 
    
 
  

  
    
 
  
 
  
  
    
    
  
 
  
  
    
 
 
   
  
 
  
  
  
 
    
T
 
 
  
  
 
    
 
 
 
   
     


 
    
  
  
  
 
 
  
 

    
 
 
 
 
 
 

 
 
 
   
    
  
U
 
V
     
 
 
  
 
  
 
 
  
 
 
 
 
  
 
 
 

 
 




 
 
 
  
      
   
W
  
 
 
   
   
 
 
 
 
 
 
 
  


 
 
 
 
 
 
    
     
  
    
     

 
X
       
  
