Loading...
Loading...
Schema design best practices for OceanBase database (MySQL & Oracle modes). Covers table design, partitioning strategies, table groups, index design, and schema optimization principles. Activates for schema design, table design, partition design, index design, database design, DDL.
npx skill4agent add amber-moe/oceanbase-doc-skills oceanbase-schema-design| Aspect | MySQL Mode | Oracle Mode |
|---|---|---|
| Data Types | | |
| Schema Access | | |
| Default Index | LOCAL (for partitioned tables) | GLOBAL (for partitioned tables) |
| Time Functions | | |
| String Functions | | |
-- ✅ GOOD: Use business fields as primary key
obclient [SALES_DB]> CREATE TABLE order_table (
order_id BIGINT PRIMARY KEY,
customer_id BIGINT NOT NULL,
gmt_create TIMESTAMP DEFAULT CURRENT_TIMESTAMP, -- MySQL: CURRENT_TIMESTAMP, Oracle: SYSDATE
gmt_modified TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) COMMENT='Order table';
-- ✅ GOOD: Composite primary key
obclient [SALES_DB]> CREATE TABLE order_item_table (
order_id BIGINT,
item_id BIGINT,
PRIMARY KEY (order_id, item_id)
);gmt_creategmt_modifiedCOMMENTNOT NULLDEFAULTTINYINT UNSIGNED-- ✅ GOOD: Hash partition on high-cardinality field
obclient [SALES_DB]> CREATE TABLE order_table (
order_id BIGINT PRIMARY KEY,
customer_id BIGINT,
order_date DATE
) PARTITION BY HASH(order_id) PARTITIONS 8;
-- ✅ GOOD: Range partition for time-based data
obclient [SALES_DB]> CREATE TABLE order_log_table (
log_id BIGINT,
log_date DATE NOT NULL,
PRIMARY KEY (log_id, log_date)
) PARTITION BY RANGE COLUMNS(log_date) (
PARTITION p202401 VALUES LESS THAN('2024-02-01'),
PARTITION p202402 VALUES LESS THAN('2024-03-01'),
PARTITION pMAX VALUES LESS THAN MAXVALUE
);-- Hash partition
obclient [SALES_DB]> CREATE TABLE order_table (
order_id BIGINT PRIMARY KEY,
customer_id BIGINT
) PARTITION BY HASH(order_id) PARTITIONS 8;
-- Range partition
obclient [SALES_DB]> CREATE TABLE order_table (
order_id BIGINT,
order_date DATE NOT NULL,
PRIMARY KEY (order_id, order_date)
) PARTITION BY RANGE COLUMNS(order_date) (
PARTITION p2024Q1 VALUES LESS THAN('2024-04-01'),
PARTITION p2024Q2 VALUES LESS THAN('2024-07-01'),
PARTITION pMAX VALUES LESS THAN MAXVALUE
);
-- Composite partition (Hash + Range)
obclient [SALES_DB]> CREATE TABLE order_table (
order_id BIGINT,
customer_id BIGINT,
order_date DATE NOT NULL,
PRIMARY KEY (order_id, customer_id, order_date)
) PARTITION BY HASH(customer_id) PARTITIONS 8
SUBPARTITION BY RANGE COLUMNS(order_date) (
PARTITION p0 (
SUBPARTITION sp0_q1 VALUES LESS THAN('2024-04-01'),
SUBPARTITION sp0_q2 VALUES LESS THAN('2024-07-01')
)
-- ... more partitions
);-- ✅ GOOD: Partition pruning works
obclient [SALES_DB]> SELECT * FROM order_table WHERE order_id = 12345;
-- Execution plan shows: partitions(p1) - only one partition accessed
-- ❌ BAD: No partition pruning (missing partition key or function on partition key)
obclient [SALES_DB]> SELECT * FROM order_table WHERE customer_id = 1001;
-- Execution plan shows: all partitions scanned-- Create table group and add tables
obclient [SALES_DB]> CREATE TABLEGROUP order_tg SHARDING = 'PARTITION'
PARTITION BY HASH(customer_id) PARTITIONS 8;
obclient [SALES_DB]> CREATE TABLE order_table (
order_id BIGINT,
customer_id BIGINT,
PRIMARY KEY (order_id, customer_id)
) PARTITION BY HASH(customer_id) PARTITIONS 8;
obclient [SALES_DB]> ALTER TABLE order_table SET TABLEGROUP order_tg;
-- Now JOIN queries can use Partition Wise Join-- MySQL Mode: Default is LOCAL
obclient [SALES_DB]> CREATE INDEX idx_customer_date ON order_table(customer_id, order_date);
-- Creates LOCAL index by default
-- Create GLOBAL index explicitly
obclient [SALES_DB]> CREATE INDEX idx_customer_date ON order_table(customer_id, order_date) GLOBAL;-- ✅ GOOD: Index matches query
obclient [SALES_DB]> CREATE INDEX idx_customer_date ON order_table(customer_id, order_date);
obclient [SALES_DB]> SELECT * FROM order_table
WHERE customer_id = 1001 AND order_date >= '2024-01-01';
-- ❌ BAD: Missing leftmost column prevents index usage
obclient [SALES_DB]> SELECT * FROM order_table WHERE order_date >= '2024-01-01';
-- Execution plan shows: TABLE SCAN (full table scan)-- ✅ GOOD: High cardinality column first
obclient [SALES_DB]> CREATE INDEX idx_customer_date ON order_table(customer_id, order_date);obclient [SALES_DB]> CREATE INDEX idx_customer_date_amount ON order_table(customer_id, order_date)
STORING (total_amount, status);NOT NULLDEFAULTALTER TABLE ADD INDEXDROP INDEX