Esta lab está dedicada a la compresión de datos de tablas e índices en Db2. El foco está en tablas con organización por filas, ilustrando decisiones prácticas entre COMPRESS YES STATIC, COMPRESS YES ADAPTIVE, VALUE COMPRESSION y compresión de índices.
1. Objetivos de la lab
Al final deberías poder:
- Distinguir las opciones actuales de compresión para tablas row-organized en Db2
- Estimar ganancias en tablas sin compresión activa
- Estimar ganancias adicionales en tablas que ya están comprimidas
- Estimar ganancias potenciales para índices sin compresión
- Activar compresión para tablas e índices
- Reorganizar los objetos para materializar la compresión
2. Software necesario y cómo obtenerlo
Para esta lab usa preferentemente:
- Db2 LUW 12.1 o 11.5.x en Linux. Community Edition es suficiente.
- Una cuenta con privilegios de propietario de la instancia
Puedes obtener IBM Db2 a través del canal oficial de IBM para descargas del producto.
3. Opciones actuales de compresión en tablas con organización por filas
Cuando la tabla está organizada por filas, las opciones relevantes son las siguientes:
| Opción | Cláusula típica | Uso principal |
|---|---|---|
| Classic row compression | COMPRESS YES STATIC | Diccionario estable, útil cuando quieres una compresión predecible tras REORG |
| Adaptive compression | COMPRESS YES ADAPTIVE | Diccionario adaptativo, normalmente la opción más interesante para tablas OLTP con evolución continua de datos |
| Value compression | ACTIVATE VALUE COMPRESSION | Elimina almacenamiento redundante de NULL, cadenas vacías y valores repetidos en columnas específicas |
| System default compression | ALTER col COMPRESS SYSTEM DEFAULT | Evita almacenar explícitamente valores default del sistema, como ceros o blancos |
| Index compression | ALTER INDEX ... COMPRESS YES | Reduce el espacio físico de los índices, especialmente en entornos OLTP y DW con muchos prefijos repetidos |
En la práctica:
- La compresión estática y la adaptativa no pueden usarse simultáneamente en la misma tabla
- Value compression puede combinarse con uno de los dos modos de row compression
- La compresión de índices se controla por separado
Qué distingue STATIC de ADAPTIVE
En ambos casos, Db2 reduce el espacio ocupado por las filas sustituyendo patrones de datos repetidos por símbolos que ocupan menos espacio. La diferencia real está en dónde se establece el diccionario de compresión y con qué frecuencia puede adaptarse al patrón real de los datos.
COMPRESS YES STATIC
En la compresión estática, Db2 usa solo un diccionario global. Ese diccionario intenta capturar los patrones más repetidos encontrados en una muestra representativa de toda la tabla.
- El diccionario global puede crearse automáticamente cuando se alcanza un cierto umbral de datos insertados, o puede crearse mediante
REORG. - Una vez creado, ese diccionario no se ajusta continuamente a los patrones locales de datos de cada página
STATIC suele funcionar bien cuando:
- La tabla tiene patrones de fila muy repetitivos
- Los valores más comunes cambian poco con el tiempo
COMPRESS YES ADAPTIVE
En la compresión adaptativa, Db2 usa dos capas de compresión:
- El mismo diccionario global usado en la compresión estática
- Diccionarios adicionales a nivel de páginas específicas, que permiten comprimir de forma eficaz patrones de repetición locales
Db2 puede crear dinámicamente diccionarios de compresión a nivel de página, basándose en los patrones repetidos existentes en esa página. Si es necesario, ese diccionario local puede recrearse automáticamente más tarde.
El diccionario global sigue existiendo y sigue comprimiendo patrones globales. La ganancia adicional del modo adaptativo viene de una segunda capa de compresión, que captura la repetición local que el diccionario global no representa tan bien y sustituye los valores repetidos localmente por símbolos mapeados mediante un diccionario de página.
La compresión adaptativa suele ser una buena apuesta cuando:
- Existen muchas columnas opcionales
- Hay cadenas de texto con repetición parcial, pero no totalmente uniforme a lo largo de la tabla
- El perfil de los datos cambia con el tiempo, por ejemplo por canales, campañas, estados operativos o nuevos tipos de carga
Imagina una tabla de pedidos como la de esta lab:
- Algumas páginas ficam dominadas por encomendas
ONLINE - Outras acumulam mais encomendas
PARTNER - Certos blocos têm mais
remarks,promo_codeegift_message - Outros têm combinações diferentes de
shipping_mode,sales_repouapproval_code
Esta lab no establece la compresión adaptativa como primera elección. Primero mide:
PCTPAGESSAVED_STATICPCTPAGESSAVED_ADAPTIVE
y solo después decide. Si la diferencia es irrelevante, el diccionario global ya está haciendo la mayor parte del trabajo y la compresión estática puede ser suficiente. Si la diferencia es significativa, eso indica que la compresión adaptativa puede explotar repetición local adicional para obtener una compresión más eficiente.
¿Y las tablas con organización por columnas?
Las tablas con organización por columnas tienen sus propios mecanismos de compresión. Ese tema es importante, pero no es el ámbito de esta lab.
Para este artículo:
- Vamos a trabajar solo con tablas cuyos datos están organizados por filas (
TABLEORG = 'R') - La función
SYSPROC.ADMIN_GET_TAB_COMPRESS_INFOes específica de row compression y devuelve cero filas para tablas column-organized
4. Crear la base de datos de la lab
Antes de crear la base de datos, cámbiate a la cuenta propietaria de la instancia Db2.
Exemplo:
su - db2inst1Si en tu entorno el usuario propietario de la instancia tiene otro nombre, sustituye db2inst1 por el nombre correcto.
Ahora crea la base de datos:
db2 "create database COMPLAB pagesize 32768"5. Crear los objetos del schema
Vamos a crear los objetos de un escenario de negocio simple, pero suficiente para mostrar compresión en datos e índices.
Además de las tablas principales, vamos a crear una tabla pequeña y una tabla volatile que quedarán excluidas del análisis de compresión.
cat > /tmp/complab_schema.sql <<'SQL'
CONNECT TO COMPLAB;
CREATE SCHEMA biz;
CREATE TABLE biz.customer_master
(
customer_id INTEGER NOT NULL,
customer_name VARCHAR(80) NOT NULL,
segment VARCHAR(20) NOT NULL,
country_code CHAR(2) NOT NULL,
region_name VARCHAR(20) NOT NULL,
email_address VARCHAR(120),
phone_number VARCHAR(24),
marketing_opt_in SMALLINT NOT NULL DEFAULT 0,
credit_class CHAR(1) NOT NULL DEFAULT 'B',
status_code CHAR(1) NOT NULL DEFAULT 'A',
comments VARCHAR(160),
created_ts TIMESTAMP NOT NULL,
filler_code CHAR(12) NOT NULL DEFAULT 'STANDARD',
PRIMARY KEY (customer_id)
);
CREATE TABLE biz.sales_order
(
order_id BIGINT NOT NULL,
customer_id INTEGER NOT NULL,
order_date DATE NOT NULL,
channel_code VARCHAR(12) NOT NULL,
order_status VARCHAR(16) NOT NULL,
country_code CHAR(2) NOT NULL,
currency_code CHAR(3) NOT NULL,
payment_method VARCHAR(20) NOT NULL,
shipping_mode VARCHAR(20) NOT NULL,
sales_rep VARCHAR(30) NOT NULL,
promo_code VARCHAR(20),
approval_code CHAR(12),
gift_message VARCHAR(120),
remarks VARCHAR(200),
fraud_score SMALLINT NOT NULL DEFAULT 0,
total_amount DECIMAL(13,2) NOT NULL,
last_update_ts TIMESTAMP NOT NULL,
PRIMARY KEY (order_id)
);
CREATE TABLE biz.sales_order_line
(
line_id BIGINT NOT NULL,
order_id BIGINT NOT NULL,
line_no SMALLINT NOT NULL,
sku_code VARCHAR(30) NOT NULL,
product_family VARCHAR(30) NOT NULL,
warehouse_code CHAR(4) NOT NULL,
tax_code CHAR(3) NOT NULL,
quantity SMALLINT NOT NULL,
unit_price DECIMAL(11,2) NOT NULL,
discount_pct DECIMAL(5,2) NOT NULL DEFAULT 0,
serial_number VARCHAR(40),
line_comment VARCHAR(120),
backorder_flag SMALLINT NOT NULL DEFAULT 0,
fulfilled_flag SMALLINT NOT NULL DEFAULT 1,
PRIMARY KEY (line_id)
);
CREATE TABLE biz.small_reference
(
ref_code CHAR(4) NOT NULL,
ref_group VARCHAR(20) NOT NULL,
ref_description VARCHAR(80) NOT NULL,
PRIMARY KEY (ref_code)
);
CREATE TABLE biz.session_work_queue
(
queue_id BIGINT NOT NULL,
session_token CHAR(24) NOT NULL,
worker_name VARCHAR(30) NOT NULL,
payload_type VARCHAR(20) NOT NULL,
payload_ref VARCHAR(40),
status_code CHAR(1) NOT NULL,
created_ts TIMESTAMP NOT NULL,
PRIMARY KEY (queue_id)
);
ALTER TABLE biz.session_work_queue VOLATILE CARDINALITY;
CREATE TABLE biz.tab_comp_baseline
(
tabname VARCHAR(128) NOT NULL,
pre_npages INTEGER NOT NULL,
pagesize INTEGER NOT NULL,
st_pct SMALLINT NOT NULL,
ad_pct SMALLINT NOT NULL,
st_mb DECIMAL(20,2) NOT NULL,
ad_mb DECIMAL(20,2) NOT NULL,
PRIMARY KEY (tabname)
);
CREATE INDEX biz.ix_order_customer_date
ON biz.sales_order (customer_id, order_date);
CREATE INDEX biz.ix_order_status_country
ON biz.sales_order (order_status, country_code);
CREATE INDEX biz.ix_order_salesrep
ON biz.sales_order (sales_rep);
CREATE INDEX biz.ix_line_order
ON biz.sales_order_line (order_id);
CREATE INDEX biz.ix_line_sku
ON biz.sales_order_line (sku_code);
CREATE INDEX biz.ix_line_wh_family
ON biz.sales_order_line (warehouse_code, product_family);
CREATE INDEX biz.ix_queue_status
ON biz.session_work_queue (status_code, created_ts);
COMMIT;
CONNECT RESET;
SQL
db2 -tvf /tmp/complab_schema.sql6. Generar y cargar datos representativos
Vamos a cargar datos con patrones típicos de negocio:
- Códigos de país, canales, métodos de pago y estados con fuerte repetición
- Columnas opcionales con muchos
NULL - Textos semirrepetitivos
- Volumen suficiente para que la compresión muestre resultados visibles
- Una tabla pequeña y una tabla
VOLATILEque no justifican evaluación
6.1 Cargar customer_master
cat > /tmp/complab_load_customers.sql <<'SQL'
CONNECT TO COMPLAB;
INSERT INTO biz.customer_master
WITH d(n) AS
(
VALUES 0,1,2,3,4,5,6,7,8,9
),
nums(n) AS
(
SELECT
a.n * 10000 +
b.n * 1000 +
c.n * 100 +
d1.n * 10 +
e.n + 1
FROM d a, d b, d c, d d1, d e
WHERE
a.n * 10000 +
b.n * 1000 +
c.n * 100 +
d1.n * 10 +
e.n + 1 <= 100000
)
SELECT
n,
'Customer ' || VARCHAR(n),
CASE MOD(n, 5)
WHEN 0 THEN 'Enterprise'
WHEN 1 THEN 'Corporate'
WHEN 2 THEN 'SMB'
WHEN 3 THEN 'Retail'
ELSE 'Partner'
END,
CASE MOD(n, 6)
WHEN 0 THEN 'PT'
WHEN 1 THEN 'ES'
WHEN 2 THEN 'FR'
WHEN 3 THEN 'DE'
WHEN 4 THEN 'IT'
ELSE 'NL'
END,
CASE MOD(n, 6)
WHEN 0 THEN 'Iberia'
WHEN 1 THEN 'Iberia'
WHEN 2 THEN 'France'
WHEN 3 THEN 'DACH'
WHEN 4 THEN 'SouthEU'
ELSE 'Benelux'
END,
CASE
WHEN MOD(n, 20) = 0 THEN NULL
ELSE 'contact' || VARCHAR(MOD(n, 12000)) || '@example.com'
END,
CASE
WHEN MOD(n, 15) = 0 THEN NULL
ELSE '+351210' || RIGHT(DIGITS(100000 + MOD(n, 900000)), 6)
END,
CASE WHEN MOD(n, 4) = 0 THEN 1 ELSE 0 END,
CASE MOD(n, 4)
WHEN 0 THEN 'A'
WHEN 1 THEN 'B'
WHEN 2 THEN 'B'
ELSE 'C'
END,
CASE WHEN MOD(n, 25) = 0 THEN 'H' ELSE 'A' END,
CASE
WHEN MOD(n, 7) = 0 THEN 'Annual contract customer'
WHEN MOD(n, 11) = 0 THEN 'Prefers consolidated monthly invoice'
ELSE 'Standard sales account'
END,
TIMESTAMP('2023-01-01-08.00.00') + MOD(n, 700) DAYS,
CASE WHEN MOD(n, 10) = 0 THEN 'STANDARD' ELSE 'STANDARD' END
FROM nums
WHERE NOT EXISTS
(
SELECT 1
FROM biz.customer_master c
WHERE c.customer_id = nums.n
);
COMMIT;
CONNECT RESET;
SQL
db2 -tvf /tmp/complab_load_customers.sql6.2 Cargar sales_order
Este bloque de código crea 500000 pedidos con muchos patrones repetidos y algunas columnas dispersas. La carga se hace en lotes de 25000 filas con COMMIT entre lotes, para evitar SQL0964C en entornos con configuración de log más conservadora. NOT EXISTS hace que la carga sea repetible sin generar errores de clave duplicada.
Dentro de cada lote de 25000 filas, creamos micro-lotes locales de 250 pedidos. En cada micro-lote, varias columnas de texto largas repiten los mismos patrones locales y el mismo identificador local muchas veces, pero esos patrones cambian en el micro-lote siguiente. Hacemos esto porque queremos reproducir un escenario en el que la compresión adaptativa sea más ventajosa que la compresión estática.
db2 connect to COMPLAB
for start_n in 1 25001 50001 75001 100001 125001 150001 175001 200001 225001 250001 275001 300001 325001 350001 375001 400001 425001 450001 475001
do
end_n=$((start_n + 24999))
db2 "
INSERT INTO biz.sales_order
WITH d(n) AS
(
VALUES 0,1,2,3,4,5,6,7,8,9
),
nums(n) AS
(
SELECT
a.n * 100000 +
b.n * 10000 +
c.n * 1000 +
d1.n * 100 +
e.n * 10 +
f.n + 1
FROM d a, d b, d c, d d1, d e, d f
WHERE
a.n * 100000 +
b.n * 10000 +
c.n * 1000 +
d1.n * 100 +
e.n * 10 +
f.n + 1 BETWEEN ${start_n} AND ${end_n}
)
SELECT
BIGINT(n),
1 + MOD(n, 100000),
DATE('2023-01-01') + MOD(n, 730) DAYS,
CASE MOD(n, 4)
WHEN 0 THEN 'ONLINE'
WHEN 1 THEN 'PARTNER'
WHEN 2 THEN 'DIRECT'
ELSE 'FIELD'
END,
CASE MOD(n, 6)
WHEN 0 THEN 'CREATED'
WHEN 1 THEN 'PAID'
WHEN 2 THEN 'ALLOCATED'
WHEN 3 THEN 'SHIPPED'
WHEN 4 THEN 'CLOSED'
ELSE 'CLOSED'
END,
CASE MOD(n, 6)
WHEN 0 THEN 'PT'
WHEN 1 THEN 'ES'
WHEN 2 THEN 'FR'
WHEN 3 THEN 'DE'
WHEN 4 THEN 'IT'
ELSE 'NL'
END,
CASE MOD(n, 3)
WHEN 0 THEN 'EUR'
WHEN 1 THEN 'EUR'
ELSE 'USD'
END,
CASE MOD(n, 5)
WHEN 0 THEN 'CARD'
WHEN 1 THEN 'CARD'
WHEN 2 THEN 'TRANSFER'
WHEN 3 THEN 'TRANSFER'
ELSE 'INVOICE'
END,
CASE MOD(n, 4)
WHEN 0 THEN 'STANDARD'
WHEN 1 THEN 'STANDARD'
WHEN 2 THEN 'EXPRESS'
ELSE 'PICKUP'
END,
'REP_' || RIGHT(DIGITS(100 + MOD(n, 35)), 3),
CASE
WHEN MOD(n, 5) IN (0,1,2,3) THEN
'L'
|| RIGHT(DIGITS(100000 + INTEGER((n - 1) / 250)), 6)
|| '-P'
|| RIGHT(DIGITS(1000 + MOD(INTEGER((n - 1) / 250), 97)), 4)
WHEN MOD(n, 15) = 0 THEN
'X'
|| RIGHT(DIGITS(100000 + INTEGER((n - 1) / 250)), 6)
|| '-P'
|| RIGHT(DIGITS(1000 + MOD(INTEGER((n - 1) / 250), 53)), 4)
ELSE NULL
END,
CASE
WHEN MOD(n, 6) IN (0,1,2,3) THEN 'APR' || RIGHT(DIGITS(100000000 + MOD(n, 900000000)), 9)
ELSE NULL
END,
CASE
WHEN MOD(n, 6) <> 5 THEN
'LOC'
|| RIGHT(DIGITS(100000 + INTEGER((n - 1) / 250)), 6)
|| ' wrap pack LOC'
|| RIGHT(DIGITS(100000 + INTEGER((n - 1) / 250)), 6)
|| ' insert note LOC'
|| RIGHT(DIGITS(100000 + INTEGER((n - 1) / 250)), 6)
|| ' carrier tag LOC'
|| RIGHT(DIGITS(100000 + INTEGER((n - 1) / 250)), 6)
ELSE NULL
END,
CASE
WHEN MOD(n, 10) = 0 THEN
'LOC'
|| RIGHT(DIGITS(100000 + INTEGER((n - 1) / 250)), 6)
|| ' route bundle LOC'
|| RIGHT(DIGITS(100000 + INTEGER((n - 1) / 250)), 6)
|| ' route bundle LOC'
|| RIGHT(DIGITS(100000 + INTEGER((n - 1) / 250)), 6)
|| ' route bundle LOC'
|| RIGHT(DIGITS(100000 + INTEGER((n - 1) / 250)), 6)
|| ' route bundle priority desk hold'
WHEN MOD(n, 14) = 0 THEN
'LOC'
|| RIGHT(DIGITS(100000 + INTEGER((n - 1) / 250)), 6)
|| ' split stage LOC'
|| RIGHT(DIGITS(100000 + INTEGER((n - 1) / 250)), 6)
|| ' split stage LOC'
|| RIGHT(DIGITS(100000 + INTEGER((n - 1) / 250)), 6)
|| ' split stage LOC'
|| RIGHT(DIGITS(100000 + INTEGER((n - 1) / 250)), 6)
|| ' split stage late dock'
ELSE
'LOC'
|| RIGHT(DIGITS(100000 + INTEGER((n - 1) / 250)), 6)
|| ' pack wave LOC'
|| RIGHT(DIGITS(100000 + INTEGER((n - 1) / 250)), 6)
|| ' pack wave LOC'
|| RIGHT(DIGITS(100000 + INTEGER((n - 1) / 250)), 6)
|| ' pack wave LOC'
|| RIGHT(DIGITS(100000 + INTEGER((n - 1) / 250)), 6)
|| ' pack wave regular dock'
END,
CASE
WHEN MOD(n, 50) = 0 THEN 90
WHEN MOD(n, 10) = 0 THEN 30
ELSE 0
END,
DECIMAL(20 + MOD(n, 8000) + (MOD(n, 100) / 100.0), 13, 2),
TIMESTAMP('2024-01-01-09.00.00') + MOD(n, 365) DAYS + MOD(n, 86400) SECONDS
FROM nums nsrc
WHERE NOT EXISTS
(
SELECT 1
FROM biz.sales_order so
WHERE so.order_id = BIGINT(nsrc.n)
)"
db2 commit
done
db2 connect reset6.3 Cargar sales_order_line
Este bloque de código genera dos filas por pedido, lo que producirá 1000000 de filas con repetición útil para compresión de datos y de índices. También aquí usamos lotes con COMMIT, y el filtro NOT EXISTS evita duplicados si el bloque se repite. En este caso usamos bloques de 25000 pedidos cada vez.
Igual que en sales_order, introducimos patrones largos que se repiten con fuerza por micro-lotes locales de 250 pedidos, pero que cambian en el micro-lote siguiente.
db2 connect to COMPLAB
for start_id in 1 25001 50001 75001 100001 125001 150001 175001 200001 225001 250001 275001 300001 325001 350001 375001 400001 425001 450001 475001
do
end_id=$((start_id + 24999))
db2 "
INSERT INTO biz.sales_order_line
SELECT
BIGINT(o.order_id * 10 + l.line_no),
o.order_id,
l.line_no,
'SKU-' || RIGHT(DIGITS(100000 + MOD(o.order_id + l.line_no, 2500)), 6),
CASE MOD(o.order_id + l.line_no, 6)
WHEN 0 THEN 'LAPTOP'
WHEN 1 THEN 'SERVER'
WHEN 2 THEN 'STORAGE'
WHEN 3 THEN 'NETWORK'
WHEN 4 THEN 'SOFTWARE'
ELSE 'SERVICE'
END,
CASE MOD(o.order_id + l.line_no, 4)
WHEN 0 THEN 'LISB'
WHEN 1 THEN 'MADR'
WHEN 2 THEN 'PARI'
ELSE 'FRAN'
END,
CASE MOD(o.order_id + l.line_no, 3)
WHEN 0 THEN 'NOR'
WHEN 1 THEN 'RED'
ELSE 'RED'
END,
SMALLINT(1 + MOD(o.order_id + l.line_no, 5)),
DECIMAL(15 + MOD(o.order_id + l.line_no, 900) + (MOD(o.order_id, 100) / 100.0), 11, 2),
DECIMAL(CASE WHEN MOD(o.order_id + l.line_no, 8) = 0 THEN 10.00 ELSE 0.00 END, 5, 2),
CASE
WHEN MOD(o.order_id + l.line_no, 20) = 0 THEN
'SN'
|| RIGHT(DIGITS(100000 + INTEGER((o.order_id - 1) / 250)), 6)
|| '-'
|| RIGHT(DIGITS(100000 + MOD(o.order_id, 900000)), 6)
ELSE NULL
END,
CASE
WHEN MOD(o.order_id + l.line_no, 9) = 0 THEN
'LOC'
|| RIGHT(DIGITS(100000 + INTEGER((o.order_id - 1) / 250)), 6)
|| ' bundle step LOC'
|| RIGHT(DIGITS(100000 + INTEGER((o.order_id - 1) / 250)), 6)
|| ' bundle step LOC'
|| RIGHT(DIGITS(100000 + INTEGER((o.order_id - 1) / 250)), 6)
|| ' bundle step'
ELSE
'LOC'
|| RIGHT(DIGITS(100000 + INTEGER((o.order_id - 1) / 250)), 6)
|| ' pick step LOC'
|| RIGHT(DIGITS(100000 + INTEGER((o.order_id - 1) / 250)), 6)
|| ' pick step LOC'
|| RIGHT(DIGITS(100000 + INTEGER((o.order_id - 1) / 250)), 6)
|| ' pick step'
END,
CASE WHEN MOD(o.order_id + l.line_no, 17) = 0 THEN 1 ELSE 0 END,
CASE WHEN MOD(o.order_id + l.line_no, 13) = 0 THEN 0 ELSE 1 END
FROM biz.sales_order o,
(VALUES 1, 2) AS l(line_no)
WHERE o.order_id BETWEEN ${start_id} AND ${end_id}
AND NOT EXISTS
(
SELECT 1
FROM biz.sales_order_line sol
WHERE sol.line_id = BIGINT(o.order_id * 10 + l.line_no)
)"
db2 commit
done
db2 connect reset6.4 Carga de la tabla pequeña y de la tabla VOLATILE
cat > /tmp/complab_load_auxiliary.sql <<'SQL'
CONNECT TO COMPLAB;
INSERT INTO biz.small_reference
SELECT *
FROM
(
VALUES
('PT01', 'COUNTRY', 'Portugal'),
('ES01', 'COUNTRY', 'Spain'),
('FR01', 'COUNTRY', 'France'),
('DE01', 'COUNTRY', 'Germany'),
('IT01', 'COUNTRY', 'Italy'),
('NL01', 'COUNTRY', 'Netherlands'),
('ONL1', 'CHANNEL', 'Online direct channel'),
('PAR1', 'CHANNEL', 'Partner resale channel'),
('DIR1', 'CHANNEL', 'Direct sales channel'),
('FLD1', 'CHANNEL', 'Field account channel')
) AS src(ref_code, ref_group, ref_description)
WHERE NOT EXISTS
(
SELECT 1
FROM biz.small_reference r
WHERE r.ref_code = src.ref_code
);
INSERT INTO biz.session_work_queue
WITH d(n) AS
(
VALUES 0,1,2,3,4,5,6,7,8,9
),
nums(n) AS
(
SELECT
a.n * 1000 +
b.n * 100 +
c.n * 10 +
d1.n + 1
FROM d a, d b, d c, d d1
WHERE
a.n * 1000 +
b.n * 100 +
c.n * 10 +
d1.n + 1 <= 5000
)
SELECT
BIGINT(n),
'TOK' || RIGHT(DIGITS(100000000 + MOD(n, 900000000)), 8) || RIGHT(DIGITS(100000000 + MOD(n * 7, 900000000)), 8) || RIGHT(DIGITS(1000 + MOD(n, 9000)), 5),
'WORKER_' || RIGHT(DIGITS(100 + MOD(n, 20)), 3),
CASE MOD(n, 4)
WHEN 0 THEN 'ALLOC'
WHEN 1 THEN 'PICK'
WHEN 2 THEN 'PACK'
ELSE 'SHIP'
END,
CASE
WHEN MOD(n, 5) = 0 THEN 'ORD-' || VARCHAR(100000 + MOD(n, 500000))
ELSE NULL
END,
CASE MOD(n, 3)
WHEN 0 THEN 'N'
WHEN 1 THEN 'R'
ELSE 'D'
END,
TIMESTAMP('2026-01-01-00.00.00') + MOD(n, 30) DAYS + MOD(n, 86400) SECONDS
FROM nums
WHERE NOT EXISTS
(
SELECT 1
FROM biz.session_work_queue q
WHERE q.queue_id = BIGINT(nums.n)
);
COMMIT;
CONNECT RESET;
SQL
db2 -tvf /tmp/complab_load_auxiliary.sql7. Recoger estadísticas y establecer una baseline
Antes de estimar compresión, actualizamos las estadísticas:
cat > /tmp/complab_runstats_before.sql <<'SQL'
CONNECT TO COMPLAB;
RUNSTATS ON TABLE biz.customer_master WITH DISTRIBUTION AND DETAILED INDEXES ALL;
RUNSTATS ON TABLE biz.sales_order WITH DISTRIBUTION AND DETAILED INDEXES ALL;
RUNSTATS ON TABLE biz.sales_order_line WITH DISTRIBUTION AND DETAILED INDEXES ALL;
RUNSTATS ON TABLE biz.small_reference WITH DISTRIBUTION AND DETAILED INDEXES ALL;
RUNSTATS ON TABLE biz.session_work_queue WITH DISTRIBUTION AND DETAILED INDEXES ALL;
CONNECT RESET;
SQL
db2 -tvf /tmp/complab_runstats_before.sql8. Estimación de compresión para tablas sin compresión activa
Esta es la primera situación operativa importante: tablas con organización por filas y todavía sin compresión activa.
Leyenda de los encabezados:
| Encabezado | Significado |
|---|---|
tab | Nombre de la tabla |
npg | NPAGES actual |
card | Cardinalidad estimada de la tabla |
psz | Tamaño de página del table space |
mode | Modo actual de row compression |
cur_pct | Porcentaje actual de páginas ahorradas |
st_pct | Estimación de ahorro con STATIC |
st_row | Tamaño medio estimado de la fila con STATIC |
st_pages | Páginas estimadas ahorradas con STATIC |
st_mb | MB estimados ahorrados con STATIC |
ad_pct | Estimación de ahorro con ADAPTIVE |
ad_row | Tamaño medio estimado de la fila con ADAPTIVE |
ad_pages | Páginas estimadas ahorradas con ADAPTIVE |
ad_mb | MB estimados ahorrados con ADAPTIVE |
db2 connect to COMPLAB
db2 "
SELECT
CAST(RTRIM(c.tabname) AS VARCHAR(24)) AS tab,
CAST(c.npages AS VARCHAR(8)) AS npg,
CAST(c.card AS VARCHAR(12)) AS card,
CAST(c.pagesize AS VARCHAR(8)) AS psz,
CAST(CASE WHEN ci.rowcompmode IN ('A', 'S') THEN ci.rowcompmode ELSE '-' END AS VARCHAR(4)) AS mode,
CAST(ci.pctpagessaved_current AS VARCHAR(6)) AS cur_pct,
CAST(ci.pctpagessaved_static AS VARCHAR(6)) AS st_pct,
CAST(ci.avgrowsize_static AS VARCHAR(8)) AS st_row,
CAST(DECIMAL((DECIMAL(c.npages,20,2) * ci.pctpagessaved_static / 100.0), 20, 2) AS VARCHAR(12)) AS st_pages,
CAST(DECIMAL((DECIMAL(c.npages,20,2) * ci.pctpagessaved_static / 100.0) * c.pagesize / 1048576.0, 20, 2) AS VARCHAR(10)) AS st_mb,
CAST(ci.pctpagessaved_adaptive AS VARCHAR(6)) AS ad_pct,
CAST(ci.avgrowsize_adaptive AS VARCHAR(8)) AS ad_row,
CAST(DECIMAL((DECIMAL(c.npages,20,2) * ci.pctpagessaved_adaptive / 100.0), 20, 2) AS VARCHAR(12)) AS ad_pages,
CAST(DECIMAL((DECIMAL(c.npages,20,2) * ci.pctpagessaved_adaptive / 100.0) * c.pagesize / 1048576.0, 20, 2) AS VARCHAR(10)) AS ad_mb
FROM
(
SELECT
t.tabschema,
t.tabname,
t.npages,
t.card,
ts.pagesize
FROM syscat.tables t
JOIN syscat.tablespaces ts
ON ts.tbspace = t.tbspace
WHERE t.tabschema = 'BIZ'
AND t.type = 'T'
AND t.tableorg = 'R'
AND t.compression = 'N'
AND t.card > 0
) AS c,
TABLE(SYSPROC.ADMIN_GET_TAB_COMPRESS_INFO(c.tabschema, c.tabname)) AS ci
WHERE ci.object_type = 'DATA'
ORDER BY c.npages DESC"
db2 connect resetInterpretación:
st_pctestima la ganancia si activas classic row compressionad_pctestima la ganancia si activas adaptive compressionst_mbyad_mbtraducen el porcentaje a espacio físico potencialmente ahorrado
9. Estimación por schema con filtrado previo
Esta es la forma más útil cuando quieres trabajar por lotes, pero sin evaluar todo indiscriminadamente. El ejemplo siguiente filtra previamente por schema, tamaño mínimo de tabla y excluye tablas volátiles. Para mantener la lectura enfocada en la decisión, la salida muestra solo las columnas que ayudan a comparar rápidamente STATIC y ADAPTIVE.
db2 connect to COMPLAB
db2 "
WITH candidates AS
(
SELECT
t.tabschema,
t.tabname,
t.npages,
t.card,
ts.pagesize
FROM syscat.tables t
JOIN syscat.tablespaces ts
ON ts.tbspace = t.tbspace
WHERE t.tabschema = 'BIZ'
AND t.type = 'T'
AND t.tableorg = 'R'
AND t.card > 0
AND t.npages > 1000
AND t.compression = 'N'
AND COALESCE(t.volatile, ' ') <> 'C'
)
SELECT
CAST(RTRIM(c.tabname) AS VARCHAR(24)) AS tab,
CAST(c.npages AS VARCHAR(8)) AS npg,
CAST(ci.pctpagessaved_static AS VARCHAR(6)) AS st_pct,
CAST(DECIMAL((DECIMAL(c.npages,20,2) * ci.pctpagessaved_static / 100.0), 20, 2) AS VARCHAR(12)) AS st_pages,
CAST(DECIMAL((DECIMAL(c.npages,20,2) * ci.pctpagessaved_static / 100.0) * c.pagesize / 1048576.0, 20, 2) AS VARCHAR(10)) AS st_mb,
CAST(ci.pctpagessaved_adaptive AS VARCHAR(6)) AS ad_pct,
CAST(DECIMAL((DECIMAL(c.npages,20,2) * ci.pctpagessaved_adaptive / 100.0), 20, 2) AS VARCHAR(12)) AS ad_pages,
CAST(DECIMAL((DECIMAL(c.npages,20,2) * ci.pctpagessaved_adaptive / 100.0) * c.pagesize / 1048576.0, 20, 2) AS VARCHAR(10)) AS ad_mb
FROM candidates c,
TABLE
(
SYSPROC.ADMIN_GET_TAB_COMPRESS_INFO(c.tabschema, c.tabname)
) AS ci
WHERE ci.object_type = 'DATA'
ORDER BY
c.npages DESC,
c.card DESC"
db2 connect resetNotas prácticas sobre los filtros:
t.tableorg = 'R'impide que tablas con organización por columnas entren en el análisist.npages > 1000evita perder tiempo con objetos demasiado pequeñosCOALESCE(t.volatile, ' ') <> 'C'deja fuera tablas declaradas como volátiles
Antes de avanzar, conviene verificar explícitamente por qué cada tabla se incluye o se excluye del análisis:
db2 connect to COMPLAB
db2 "
SELECT
CAST(RTRIM(tabname) AS VARCHAR(24)) AS tab,
CAST(npages AS VARCHAR(8)) AS npg,
CAST(COALESCE(volatile, ' ') AS VARCHAR(4)) AS vol,
CAST(compression AS VARCHAR(4)) AS comp,
CASE
WHEN tableorg <> 'R' THEN 'excluded: not row-organized'
WHEN card = 0 THEN 'excluded: no useful statistics'
WHEN COALESCE(volatile, ' ') = 'C' THEN 'excluded: volatile table'
WHEN npages <= 1000 THEN 'excluded: too small'
WHEN compression <> 'N' THEN 'excluded: already compressed'
ELSE 'included in evaluation'
END AS reason
FROM syscat.tables
WHERE tabschema = 'BIZ'
AND type = 'T'
ORDER BY tabname"
db2 connect resetEn esta lab deberías observar, en condiciones normales:
SMALL_REFERENCEexcluida por tamañoSESSION_WORK_QUEUEexcluida por estar marcada comoVOLATILECUSTOMER_MASTER,SALES_ORDERySALES_ORDER_LINEincluidas en el lote de evaluación
10. Comparar STATIC y ADAPTIVE antes de la compresión
Antes de activar compresión, este análisis permite comparar directamente STATIC y ADAPTIVE y elegir el modo más ventajoso para cada tabla.
db2 connect to COMPLAB
db2 "
WITH candidates AS
(
SELECT
t.tabschema,
t.tabname,
t.npages,
t.card,
t.compression,
ts.pagesize
FROM syscat.tables t
JOIN syscat.tablespaces ts
ON ts.tbspace = t.tbspace
WHERE t.tabschema = 'BIZ'
AND t.type = 'T'
AND t.tableorg = 'R'
AND t.card > 0
AND t.npages > 1000
AND t.compression = 'N'
AND COALESCE(t.volatile, ' ') <> 'C'
)
SELECT
CAST(RTRIM(c.tabname) AS VARCHAR(24)) AS tab,
CAST(c.npages AS VARCHAR(8)) AS npg,
CAST(ci.pctpagessaved_static AS VARCHAR(6)) AS st_pct,
CAST(ci.pctpagessaved_adaptive AS VARCHAR(6)) AS ad_pct,
CAST(ci.pctpagessaved_adaptive - ci.pctpagessaved_static AS VARCHAR(6)) AS adv_pct,
CAST(DECIMAL(
(DECIMAL(c.npages,20,2) * (ci.pctpagessaved_adaptive - ci.pctpagessaved_static) / 100.0) * c.pagesize / 1048576.0,
20, 2
) AS VARCHAR(10)) AS extra_mb
FROM candidates c,
TABLE(SYSPROC.ADMIN_GET_TAB_COMPRESS_INFO(c.tabschema, c.tabname)) AS ci
WHERE ci.object_type = 'DATA'
ORDER BY adv_pct DESC, npg DESC"
db2 connect resetLeyenda de los encabezados:
| Encabezado | Significado |
|---|---|
tab | Nombre de la tabla |
npg | NPAGES actual |
st_pct | Estimación con STATIC |
ad_pct | Estimación con ADAPTIVE |
adv_pct | Diferencia ADAPTIVE - STATIC en puntos porcentuales |
extra_mb | MB adicionales potencialmente ahorrados por ADAPTIVE |
11. Identificar explícitamente dónde ADAPTIVE aporta ventaja
El resultado de la sección anterior sirve para elegir la tabla candidata principal. La lógica de la lab es la siguiente:
- Si una tabla grande presenta un
adv_pctmaterial, esa tabla es la mejor candidata para compresión adaptativa - Si otra tabla también se beneficia bastante de la compresión en términos absolutos, pero tiene una diferencia menor entre
STATICyADAPTIVE, sigue siendo un buen objetivo de compresión, pero puede empezar porSTATIC - Después de activar la compresión y reorganizar, los datos medidos deben confirmar estas dos ideas: la tabla elegida para
ADAPTIVEdebería acercarse a la estimación adaptativa, y la tabla dejada enSTATICpuede seguir mostrando margen adicional potencial en el análisis final
En el escenario buscado para esta lab, ambas tablas grandes deben mostrar ganancias fuertes con compresión, pero sales_order debería evidenciar la ventaja más clara de la compresión adaptativa.
12. Estimar ganancias para índices sin compresión
Para índices, el caso de uso clásico es simple: índices sin compresión física, en tablas grandes, con bastante repetición de claves o prefijos.
db2 connect to COMPLAB
db2 "
SELECT
CAST(RTRIM(indname) AS VARCHAR(28)) AS idx,
CAST(RTRIM(tabname) AS VARCHAR(24)) AS tab,
CAST(compress_attr AS VARCHAR(4)) AS attr,
CAST(index_compressed AS VARCHAR(4)) AS icomp,
CAST(pct_pages_saved AS VARCHAR(8)) AS pct_saved,
CAST(num_leaf_pages_saved AS VARCHAR(10)) AS leaf_saved
FROM TABLE
(
SYSPROC.ADMIN_GET_INDEX_COMPRESS_INFO('', 'BIZ', 'SALES_ORDER', NULL, NULL)
) AS t
ORDER BY num_leaf_pages_saved DESC"
db2 connect resetInterpretación:
COMPRESS_ATTR = 'N'eINDEX_COMPRESSED = 'N'significa índice sin compresiónPCT_PAGES_SAVEDestima el porcentaje potencial de páginas leaf ahorradasNUM_LEAF_PAGES_SAVEDtraduce la ganancia a páginas físicas
Leyenda de los encabezados:
| Encabezado | Significado |
|---|---|
idx | Nombre del índice |
tab | Tabla base |
attr | Atributo de compresión definido para el índice |
icomp | Estado actual de compresión del índice |
pct_saved | Porcentaje estimado de páginas leaf ahorradas |
leaf_saved | Número estimado de páginas leaf ahorradas |
Puedes repetir el mismo análisis para otra tabla:
db2 connect to COMPLAB
db2 "
SELECT
CAST(RTRIM(indname) AS VARCHAR(28)) AS idx,
CAST(RTRIM(tabname) AS VARCHAR(24)) AS tab,
CAST(compress_attr AS VARCHAR(4)) AS attr,
CAST(index_compressed AS VARCHAR(4)) AS icomp,
CAST(pct_pages_saved AS VARCHAR(8)) AS pct_saved,
CAST(num_leaf_pages_saved AS VARCHAR(10)) AS leaf_saved
FROM TABLE
(
SYSPROC.ADMIN_GET_INDEX_COMPRESS_INFO('', 'BIZ', 'SALES_ORDER_LINE', NULL, NULL)
) AS t
ORDER BY num_leaf_pages_saved DESC"
db2 connect reset13. Activar compresión en la tabla y en los índices
Ahora convertimos la decisión anterior en acciones concretas:
sales_orderse comprimirá conADAPTIVE, porque la estimación muestra una ventaja visible frente aSTATICsales_order_linese comprimirá conSTATIC, no porque comprima poco, sino porque la diferencia inicial frente aADAPTIVEes menor y queremos validar después si todavía existe margen adicional- Las columnas con defaults repetidos activan value compression
- Los índices relevantes también pasan a
COMPRESS YES
Antes del cambio, guardamos una baseline persistente para las dos tablas. Esa baseline se usará más adelante para comparar la estimación previa con el resultado real medido después del REORG:
db2 connect to COMPLAB
db2 "
MERGE INTO biz.tab_comp_baseline AS b
USING
(
SELECT
t.tabname,
t.npages,
ts.pagesize,
ci.pctpagessaved_static AS st_pct,
ci.pctpagessaved_adaptive AS ad_pct,
DECIMAL((DECIMAL(t.npages,20,2) * ci.pctpagessaved_static / 100.0) * ts.pagesize / 1048576.0, 20, 2) AS st_mb,
DECIMAL((DECIMAL(t.npages,20,2) * ci.pctpagessaved_adaptive / 100.0) * ts.pagesize / 1048576.0, 20, 2) AS ad_mb
FROM syscat.tables t
JOIN syscat.tablespaces ts
ON ts.tbspace = t.tbspace,
TABLE(SYSPROC.ADMIN_GET_TAB_COMPRESS_INFO(t.tabschema, t.tabname)) AS ci
WHERE t.tabschema = 'BIZ'
AND t.tabname IN ('SALES_ORDER', 'SALES_ORDER_LINE')
AND ci.object_type = 'DATA'
) AS src
ON b.tabname = src.tabname
WHEN MATCHED THEN
UPDATE SET
pre_npages = src.npages,
pagesize = src.pagesize,
st_pct = src.st_pct,
ad_pct = src.ad_pct,
st_mb = src.st_mb,
ad_mb = src.ad_mb
WHEN NOT MATCHED THEN
INSERT (tabname, pre_npages, pagesize, st_pct, ad_pct, st_mb, ad_mb)
VALUES (src.tabname, src.npages, src.pagesize, src.st_pct, src.ad_pct, src.st_mb, src.ad_mb)";
db2 "
SELECT
CAST(RTRIM(tabname) AS VARCHAR(24)) AS tab,
CAST(pre_npages AS VARCHAR(8)) AS pre_npg,
CAST(st_pct AS VARCHAR(6)) AS st_pct,
CAST(ad_pct AS VARCHAR(6)) AS ad_pct,
CAST(st_mb AS VARCHAR(10)) AS st_mb,
CAST(ad_mb AS VARCHAR(10)) AS ad_mb
FROM biz.tab_comp_baseline
WHERE tabname IN ('SALES_ORDER', 'SALES_ORDER_LINE')
ORDER BY tabname"
db2 connect resetLeyenda de los encabezados:
| Encabezado | Significado |
|---|---|
tab | Nombre de la tabla |
pre_npg | NPAGES antes de la compresión |
st_pct | Estimación con STATIC antes de la compresión |
ad_pct | Estimación con ADAPTIVE antes de la compresión |
st_mb | MB estimados ahorrados con STATIC antes de la compresión |
ad_mb | MB estimados ahorrados con ADAPTIVE antes de la compresión |
Vamos a modificar las tablas para activar la compresión.
cat > /tmp/complab_enable_compression.sql <<'SQL'
CONNECT TO COMPLAB;
ALTER TABLE biz.sales_order
ALTER fraud_score COMPRESS SYSTEM DEFAULT
COMPRESS YES ADAPTIVE
ACTIVATE VALUE COMPRESSION;
ALTER TABLE biz.sales_order_line
ALTER discount_pct COMPRESS SYSTEM DEFAULT
ALTER backorder_flag COMPRESS SYSTEM DEFAULT
ALTER fulfilled_flag COMPRESS SYSTEM DEFAULT
COMPRESS YES STATIC
ACTIVATE VALUE COMPRESSION;
ALTER INDEX biz.ix_order_customer_date COMPRESS YES;
ALTER INDEX biz.ix_order_status_country COMPRESS YES;
ALTER INDEX biz.ix_order_salesrep COMPRESS YES;
ALTER INDEX biz.ix_line_order COMPRESS YES;
ALTER INDEX biz.ix_line_sku COMPRESS YES;
ALTER INDEX biz.ix_line_wh_family COMPRESS YES;
COMMIT;
CONNECT RESET;
SQL
db2 -tvf /tmp/complab_enable_compression.sql14. Materializar los datos comprimidos
Activar las cláusulas de compresión no basta por sí solo para reformatear inmediatamente todos los datos antiguos. Para aplicar la nueva organización física, tenemos que reorganizar.
cat > /tmp/complab_reorg.sql <<'SQL'
CONNECT TO COMPLAB;
REORG TABLE biz.sales_order RESETDICTIONARY;
REORG INDEXES ALL FOR TABLE biz.sales_order ALLOW WRITE ACCESS;
REORG TABLE biz.sales_order_line RESETDICTIONARY;
REORG INDEXES ALL FOR TABLE biz.sales_order_line ALLOW WRITE ACCESS;
RUNSTATS ON TABLE biz.sales_order WITH DISTRIBUTION AND DETAILED INDEXES ALL;
RUNSTATS ON TABLE biz.sales_order_line WITH DISTRIBUTION AND DETAILED INDEXES ALL;
CONNECT RESET;
SQL
db2 -tvf /tmp/complab_reorg.sql15. Verificar las mejoras reales, con foco en SALES_ORDER
Primero confirmamos si la tabla elegida pasó efectivamente a compresión adaptativa y comparamos el ahorro actual con la baseline guardada:
db2 connect to COMPLAB
db2 "
SELECT
CAST(RTRIM(t.tabname) AS VARCHAR(24)) AS tab,
CAST(b.pre_npages AS VARCHAR(8)) AS pre_npg,
CAST(t.npages AS VARCHAR(8)) AS cur_npg,
CAST(CASE WHEN ci.rowcompmode IN ('A', 'S') THEN ci.rowcompmode ELSE '-' END AS VARCHAR(4)) AS mode,
CAST(b.st_pct AS VARCHAR(6)) AS pre_st,
CAST(b.ad_pct AS VARCHAR(6)) AS pre_ad,
CAST(ci.pctpagessaved_current AS VARCHAR(6)) AS cur_pct,
CAST(b.ad_mb AS VARCHAR(10)) AS pre_ad_mb,
CAST(DECIMAL
(
CASE
WHEN ci.pctpagessaved_current BETWEEN 0 AND 99
THEN ((DECIMAL(t.npages,20,4) * 100.0) / (100.0 - ci.pctpagessaved_current) - DECIMAL(t.npages,20,4)) * ts.pagesize / 1048576.0
ELSE NULL
END,
20, 2
) AS VARCHAR(10)) AS cur_mb
FROM syscat.tables t
JOIN syscat.tablespaces ts
ON ts.tbspace = t.tbspace
JOIN biz.tab_comp_baseline b
ON b.tabname = t.tabname,
TABLE(SYSPROC.ADMIN_GET_TAB_COMPRESS_INFO(t.tabschema, t.tabname)) AS ci
WHERE t.tabschema = 'BIZ'
AND t.tabname = 'SALES_ORDER'
AND ci.object_type = 'DATA'"
db2 connect resetEl punto a verificar aquí es simple:
ROWCOMPMODEdebe aparecer comoA.PCTPAGESSAVED_CURRENTdebe aproximarse a la baselinepre_ad.cur_mbdebe aproximarse apre_ad_mb, dentro de la variación normal causada por páginas parcialmente llenas y por el estado real del objeto.
Leyenda de los encabezados:
| Encabezado | Significado |
|---|---|
tab | Nombre de la tabla |
pre_npg | NPAGES antes de la compresión |
cur_npg | NPAGES después de la compresión |
mode | Modo actual de row compression |
pre_st | Baseline STATIC antes de la compresión |
pre_ad | Baseline ADAPTIVE antes de la compresión |
cur_pct | Ahorro actual medido |
pre_ad_mb | MB estimados con ADAPTIVE antes de la compresión |
cur_mb | MB ahorrados actualmente |
Solo después de eso tiene sentido mirar el conjunto completo.
16. Validar el resultado real después de la compresión
Primero confirmamos los atributos de las tablas:
db2 connect to COMPLAB
db2 "
SELECT
CAST(RTRIM(t.tabname) AS VARCHAR(24)) AS tab,
CAST(t.compression AS VARCHAR(4)) AS comp,
CAST(t.tableorg AS VARCHAR(4)) AS org,
CAST(CASE WHEN ci.rowcompmode IN ('A', 'S') THEN ci.rowcompmode ELSE '-' END AS VARCHAR(4)) AS mode,
CAST(ci.pctpagessaved_current AS VARCHAR(6)) AS cur_pct
FROM syscat.tables t,
TABLE(SYSPROC.ADMIN_GET_TAB_COMPRESS_INFO(t.tabschema, t.tabname)) AS ci
WHERE t.tabschema = 'BIZ'
AND t.tabname IN ('SALES_ORDER', 'SALES_ORDER_LINE')
AND ci.object_type = 'DATA'"
db2 connect resetLeyenda de los encabezados:
| Encabezado | Significado |
|---|---|
tab | Nombre de la tabla |
comp | Atributo de compresión en el catálogo |
org | Organización de la tabla |
mode | Modo actual de row compression |
cur_pct | Ahorro actual medido |
Después comparamos la ganancia actual con las estimaciones guardadas en la baseline:
db2 connect to COMPLAB
db2 "
SELECT
CAST(RTRIM(t.tabname) AS VARCHAR(24)) AS tab,
CAST(b.pre_npages AS VARCHAR(8)) AS pre_npg,
CAST(t.npages AS VARCHAR(8)) AS cur_npg,
CAST(CASE WHEN ci.rowcompmode IN ('A', 'S') THEN ci.rowcompmode ELSE '-' END AS VARCHAR(4)) AS mode,
CAST(b.st_pct AS VARCHAR(6)) AS pre_st,
CAST(b.ad_pct AS VARCHAR(6)) AS pre_ad,
CAST(ci.pctpagessaved_current AS VARCHAR(6)) AS cur_pct,
CAST(b.st_mb AS VARCHAR(10)) AS pre_st_mb,
CAST(b.ad_mb AS VARCHAR(10)) AS pre_ad_mb,
CAST(DECIMAL
(
CASE
WHEN ci.pctpagessaved_current BETWEEN 0 AND 99
THEN ((DECIMAL(t.npages,20,4) * 100.0) / (100.0 - ci.pctpagessaved_current) - DECIMAL(t.npages,20,4)) * ts.pagesize / 1048576.0
ELSE NULL
END,
20, 2
) AS VARCHAR(10)) AS cur_mb
FROM syscat.tables t
JOIN syscat.tablespaces ts
ON ts.tbspace = t.tbspace
JOIN biz.tab_comp_baseline b
ON b.tabname = t.tabname,
TABLE(SYSPROC.ADMIN_GET_TAB_COMPRESS_INFO(t.tabschema, t.tabname)) AS ci
WHERE t.tabschema = 'BIZ'
AND t.tabname IN ('SALES_ORDER', 'SALES_ORDER_LINE')
AND ci.object_type = 'DATA'"
db2 connect resetAquí la validación es importante:
sales_orderdebe mostrarmode = 'A'y uncur_pctmás cercano a la baselinepre_adque apre_stsales_order_linedebe mostrarmode = 'S'y uncur_pctpróximo a la baselinepre_st- Si
sales_order_linetodavía presenta una distancia visible entrecur_pctypre_ad, eso prepara exactamente el análisis de la sección siguiente: ya existe compresión útil aplicada, pero todavía puede haber margen adicional conADAPTIVE
Y por último validamos la compresión de los índices:
db2 connect to COMPLAB
db2 "
SELECT
CAST(RTRIM(indname) AS VARCHAR(28)) AS idx,
CAST(RTRIM(tabname) AS VARCHAR(24)) AS tab,
CAST(compress_attr AS VARCHAR(4)) AS attr,
CAST(index_compressed AS VARCHAR(4)) AS icomp,
CAST(pct_pages_saved AS VARCHAR(8)) AS pct_saved,
CAST(num_leaf_pages_saved AS VARCHAR(10)) AS leaf_saved
FROM TABLE
(
SYSPROC.ADMIN_GET_INDEX_COMPRESS_INFO('', 'BIZ', '', NULL, NULL)
) AS t
WHERE tabschema = 'BIZ'
ORDER BY tabname, indname"
db2 connect resetLeyenda de los encabezados:
| Encabezado | Significado |
|---|---|
idx | Nombre del índice |
tab | Tabla base |
attr | Atributo de compresión configurado |
icomp | Estado actual de compresión |
pct_saved | Porcentaje de páginas leaf ahorradas |
leaf_saved | Número de páginas leaf ahorradas |
17. Verificar ganancias adicionales después de la compresión
En una tabla ya comprimida, ¿existe margen adicional si el modo actual no es el mejor, o si la ganancia actual todavía está lejos de la estimación adaptativa? Observando la tabla sales_order_line, verificamos que la compresión estática aportó una ganancia fuerte, pero todavía puede existir algún beneficio adicional si adoptamos compresión adaptativa.
db2 connect to COMPLAB
db2 "
WITH candidates AS
(
SELECT
t.tabschema,
t.tabname,
t.npages,
t.card,
t.compression,
ts.pagesize
FROM syscat.tables t
JOIN syscat.tablespaces ts
ON ts.tbspace = t.tbspace
WHERE t.tabschema = 'BIZ'
AND t.type = 'T'
AND t.tableorg = 'R'
AND t.card > 0
AND t.compression <> 'N'
)
SELECT
CAST(RTRIM(c.tabname) AS VARCHAR(24)) AS tab,
CAST(c.compression AS VARCHAR(4)) AS comp,
CAST(CASE WHEN ci.rowcompmode IN ('A', 'S') THEN ci.rowcompmode ELSE '-' END AS VARCHAR(4)) AS mode,
CAST(ci.pctpagessaved_current AS VARCHAR(6)) AS cur_pct,
CAST(ci.pctpagessaved_static AS VARCHAR(6)) AS st_pct,
CAST(ci.pctpagessaved_adaptive AS VARCHAR(6)) AS ad_pct,
CAST(DECIMAL
(
CASE
WHEN ci.pctpagessaved_current BETWEEN 0 AND 99
THEN (DECIMAL(c.npages,20,4) * 100.0) / (100.0 - ci.pctpagessaved_current)
ELSE NULL
END,
20, 2
) AS VARCHAR(12)) AS unc_pages,
CAST(DECIMAL
(
CASE
WHEN ci.pctpagessaved_current BETWEEN 0 AND 99
THEN
(
((DECIMAL(c.npages,20,4) * 100.0) / (100.0 - ci.pctpagessaved_current))
* (ci.pctpagessaved_adaptive - ci.pctpagessaved_current) / 100.0
* c.pagesize
) / 1048576.0
ELSE NULL
END,
20, 2
) AS VARCHAR(10)) AS extra_mb
FROM candidates c,
TABLE
(
SYSPROC.ADMIN_GET_TAB_COMPRESS_INFO(c.tabschema, c.tabname)
) AS ci
WHERE ci.object_type = 'DATA'
ORDER BY c.npages DESC"
db2 connect resetLectura del resultado:
- Si
cur_pctya está próximo dead_pct, el espacio adicional recuperable será pequeño. - Si
mode = 'S'yad_pctes claramente superior, esa es una situación concreta para considerar compresión adaptativa.
Leyenda de los encabezados:
| Encabezado | Significado |
|---|---|
tab | Nombre de la tabla |
comp | Atributo actual de compresión en el catálogo |
mode | Modo actual de row compression (S, A o -) |
cur_pct | Ahorro actual medido |
st_pct | Estimación con STATIC |
ad_pct | Estimación con ADAPTIVE |
unc_pages | Número inferido de páginas sin compresión |
extra_mb | Ganancia adicional estimada en MB si pasas a ADAPTIVE |
18. Resumen
Esta lab mostró varios puntos operativos importantes:
- La compresión de tablas con datos organizados por filas en Db2 no recurre a una sola funcionalidad. Involucra compresión clásica estática, compresión adaptativa y compresión de valores.
ADMIN_GET_TAB_COMPRESS_INFOyADMIN_GET_INDEX_COMPRESS_INFOpermiten estimar las ganancias con compresión.- No todas las tablas deben entrar en el análisis. En esta lab, una fue excluida por ser demasiado pequeña y otra por estar marcada como
VOLATILE
Una secuencia adecuada suele ser:
1. Filtrar candidatos en función de tamaño, volatilidad y patrón de uso 2. Estimar ganancias para tablas e índices 3. Activar compresión solo en los objetos con retorno claro 4. Reorganizar y recoger estadísticas 5. Medir de nuevo
19. Limpieza
Cuando termines la lab, elimina la base de datos y los archivos temporales:
db2 force applications all
db2 drop database COMPLAB
rm -f /tmp/complab_schema.sql \
/tmp/complab_load_customers.sql \
/tmp/complab_load_orders.sql \
/tmp/complab_load_lines.sql \
/tmp/complab_load_auxiliary.sql \
/tmp/complab_runstats_before.sql \
/tmp/complab_enable_compression.sql \
/tmp/complab_reorg.sqlDocumentación útil de IBM
Para profundizar, las referencias de IBM más útiles para este tema son: