Monday, March 31, 2025

Observation about PostgreSQL's Index Only Scan behavior

 

Test Case

mytest=# \dt pgbench_accounts;
              List of relations
 Schema |       Name       | Type  |  Owner
--------+------------------+-------+----------
 public | pgbench_accounts | table | donghual
(1 row)
mytest=# delete from pgbench_accounts where aid=1;
DELETE 1
Time: 16.197 ms

Observation 1

mytest=# explain (buffers,analyze) select aid from pgbench_accounts where aid=1;
                                                                 QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------------------------
 Index Only Scan using pgbench_accounts_pkey on pgbench_accounts  (cost=0.29..8.31 rows=1 width=4) (actual time=1.692..1.693 rows=0 loops=1)
   Index Cond: (aid = 1)
   Heap Fetches: 1
   Buffers: shared hit=3 read=1 dirtied=1
 Planning Time: 0.079 ms
 Execution Time: 1.758 ms
(6 rows)

Time: 5.305 ms

Observation 2

mytest=# explain (buffers,analyze) select aid from pgbench_accounts where aid=1;
                                                                 QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------------------------
 Index Only Scan using pgbench_accounts_pkey on pgbench_accounts  (cost=0.29..8.31 rows=1 width=4) (actual time=0.023..0.023 rows=0 loops=1)
   Index Cond: (aid = 1)
   Heap Fetches: 0
   Buffers: shared hit=2
 Planning Time: 0.056 ms
 Execution Time: 0.066 ms
(6 rows)

Time: 0.414 ms

Why the first execution shows "Heap Fetches: 1" but the second shows "Heap Fetches: 0"

The difference relates to how PostgreSQL's Index Only Scan works and the visibility information in the index:

  1. First execution (Heap Fetches: 1): 

    • You just deleted the row with aid=1 

    • When PostgreSQL performs an Index Only Scan, it first checks the index • The index entry for aid=1 was still present, but PostgreSQL needed to verify if this row was visible ( not deleted) 

    • Since the visibility information wasn't current in the index's visibility map, PostgreSQL had to fetch the heap (table) page to check if the row was actually visible 

    • That's why you see "Heap Fetches: 1" - it had to check the actual table data 

    • You also see "Buffers: shared hit=3 read=1 dirtied=1" showing more I/O activity

  2. Second execution (Heap Fetches: 0): 

    • By this time, PostgreSQL had updated its visibility information 

    • The system now knew that the row with aid=1 was deleted 

    • The index's visibility map was updated to reflect this 

    • When executing the same query again, PostgreSQL could determine directly from the index that no visible rows exist with aid=1 

    • No need to check the heap (table) data, hence "Heap Fetches: 0" 

    • You also see reduced buffer activity: "Buffers: shared hit=2"

This is one of the key optimizations in PostgreSQL's Index Only Scans. The first query after a data modification often needs to do heap fetches to verify visibility, but subsequent queries can avoid these fetches once the visibility map is updated.

The execution time difference (1.758ms vs 0.066ms) clearly shows the performance benefit of avoiding those heap fetches.

Thursday, March 20, 2025

Installing Oracle Database 23ai on Amazon Linux 2023

 This guide provides steps to install Oracle Database 23ai on Amazon Linux 2023 by resolving dependency issues with the Oracle preinstall package. The steps documented here are purely for testing purpose, and never be considered as recommendation for production setup.

Problem Overview

The Oracle Database 23ai preinstall package (oracle-database-preinstall-23ai) has dependencies that conflict with Amazon Linux 2023:

  1. It requires /etc/redhat-release which doesn't exist on Amazon Linux
  2. It requires xorg-x11-utils which has been split into individual packages in Amazon Linux 2023

Solution: Create Custom RPMs

We'll create two custom RPMs to satisfy these dependencies without conflicting with existing packages.

1. Create fake-redhat-release RPM

This RPM provides the /etc/redhat-release file that Oracle's preinstall package checks for.

Step 1: Set up the RPM build environment

# Install RPM build tools
sudo yum install -y rpm-build rpmdevtools

# Set up the RPM build directory structure
rpmdev-setuptree

Step 2: Create the RPM spec file

cd ~
cat > fake-redhat-release.spec << 'EOF'
Name:           fake-redhat-release
Version:        9.0
Release:        1%{?dist}
Summary:        Fake Red Hat Enterprise Linux release file
License:        MIT

BuildArch:      noarch
Provides:       redhat-release = 9.0
Provides:       system-release = 9.0

%description
This package provides a fake /etc/redhat-release file to satisfy dependencies
for packages that require it on non-RHEL systems like Amazon Linux.

%prep
# Nothing to do

%build
# Nothing to build

%install
mkdir -p %{buildroot}/etc
echo "Red Hat Enterprise Linux release 9.0 (Plow)" > %{buildroot}/etc/redhat-release

%files
%attr(0644,root,root) /etc/redhat-release

%changelog
* Thu Mar 20 2025 User <user@example.com> - 9.0-1
- Initial package
EOF

Step 3: Build the RPM

rpmbuild -bb fake-redhat-release.spec

Step 4: Install the RPM

sudo rpm -ivh ~/rpmbuild/RPMS/noarch/fake-redhat-release-9.0-1*.rpm

2. Create dummy-xorg-x11-utils RPM

This RPM provides the virtual capability xorg-x11-utils without containing any files that would conflict with the individual X11 utility packages.

Step 1: Create the RPM spec file

cd ~
cat > dummy-xorg-x11-utils.spec << 'EOF'
Name:           dummy-xorg-x11-utils
Version:        7.5
Release:        39%{?dist}
Summary:        Dummy package that provides xorg-x11-utils
License:        MIT

BuildArch:      noarch
Provides:       xorg-x11-utils = 7.5-39
# Don't conflict with the actual utilities that obsolete xorg-x11-utils
Conflicts:      xorg-x11-utils

%description
This is a dummy package that provides the xorg-x11-utils virtual capability
without containing any files that would conflict with the individual X11
utility packages in Amazon Linux 2023.

%prep
# Nothing to do

%build
# Nothing to build

%install
# Create an empty directory structure
mkdir -p %{buildroot}

%files
# No files

%changelog
* Thu Mar 20 2025 User <user@example.com> - 7.5-39
- Initial dummy package
EOF

Step 2: Build the RPM

rpmbuild -bb dummy-xorg-x11-utils.spec

Step 3: Install the dummy package

sudo rpm -ivh ~/rpmbuild/RPMS/noarch/dummy-xorg-x11-utils-7.5-39*.rpm

3. Install Oracle Database 23ai Preinstall Package

After installing both custom RPMs, you can install the Oracle preinstall package:

sudo yum install https://yum.oracle.com/repo/OracleLinux/OL9/appstream/x86_64/getPackage/oracle-database-preinstall-23ai-1.0-2.el9.x86_64.rpm

4. Install Required X11 Utility Packages

Even with the dummy package, you should install the actual X11 utilities that Oracle might need:

sudo yum install -y xdpyinfo xev xwininfo xprop xkill xlsclients xlsatoms
After this step, you can install Oracle 23ai (FREE) RPM "oracle-database-free-23ai-1.0-1.el9.x86_64.rpm". (Link)

Notes

  • This approach is specifically for Amazon Linux 2023 and Oracle Database 23ai
  • For production environments, consider using Oracle Linux which is fully supported
  • Always refer to Oracle's official documentation for the latest requirements

[root@ip-x-2-2-x ~]# cat /etc/amazon-linux-release
Amazon Linux release 2023.6.20250303 (Amazon Linux)
[root@ip-x-2-2-x ~]# 
[root@ip-x-2-2-x ~]# rpm -qa|grep oracle-database-free-23ai-1.0-1.x86_64
oracle-database-free-23ai-1.0-1.x86_64