| Lesson 5 | National Character Sets |
| Objective | Choose a national character set for an Oracle 26ai database. |
CHAR, VARCHAR2, CLOB, and LONG columns, identifiers, and stored SQL/PL/SQL source, almost always AL32UTF8 in a 26ai database. What we didn't cover is that every Oracle database actually carries two character sets, not one. The second is the national character set, and it applies exclusively to a narrower set of column types: NCHAR, NVARCHAR2, and NCLOB.
The NCHAR, NVARCHAR2, and NCLOB data types were originally designed as an escape hatch: a way to guarantee Unicode-capable storage for a specific set of columns, even in databases whose primary character set wasn't Unicode. In practice today, with AL32UTF8 as the near-universal default database character set, that original motivation rarely applies — your regular VARCHAR2 columns are already Unicode-capable. Where the national character set types still earn their keep is in a handful of narrower cases: applications that need a fixed-width encoding for predictable in-memory processing, or legacy schemas and third-party products that were built around the NCHAR family and expect it to behave a particular way.
Before choosing a national character set, it's worth asking honestly whether your application needs NCHAR columns at all, or whether standard VARCHAR2 columns on an AL32UTF8 database character set already cover the requirement.
AL16UTF16 — a fixed-width Unicode encoding using 2 bytes per character. Predictable storage size and simpler in-memory operations make it a good fit for applications with heavy multilingual NCHAR usage. This has been the default national character set since Oracle 12c, and remains the default well into the 26ai release line.UTF8 — a variable-width Unicode encoding using 1 to 3 bytes per character (distinct from the database-character-set value AL32UTF8, despite the naming similarity). Its variable width can save storage for data that's mostly ASCII with occasional multi-byte characters, at the cost of more processing overhead per multi-byte character.AL16UTF16 is the right call — it's the default for a reason, and most applications never have a strong enough storage-efficiency argument to justify the added complexity of the variable-width alternative.
Like the database character set, this is a creation-time decision:
AL16UTF16 is preselected; switch to UTF8 only if you have a specific reason to.CREATE DATABASE: specify it directly:
CREATE DATABASE your_database_name
...
NATIONAL CHARACTER SET AL16UTF16;
Substitute UTF8 for AL16UTF16 if you've deliberately chosen the variable-width option.
NLS_DATABASE_PARAMETERS:
SELECT PARAMETER, VALUE
FROM NLS_DATABASE_PARAMETERS
WHERE PARAMETER IN ('NLS_CHARACTERSET', 'NLS_NCHAR_CHARACTERSET');
PARAMETER VALUE
------------------------ ----------------
NLS_CHARACTERSET AL32UTF8
NLS_NCHAR_CHARACTERSET AL16UTF16
That's a typical, healthy 26ai configuration: AL32UTF8 handling the bulk of your data, AL16UTF16 standing by for any NCHAR-family columns you actually use. Neither NLS_CHARACTERSET nor NLS_NCHAR_CHARACTERSET can be changed with ALTER SESSION — they aren't session-level settings at all. They're fixed properties of the database itself, set once at creation.
NCHAR and NVARCHAR2 columns, length is specified in characters, not bytes — the opposite convention from CHAR and VARCHAR2, and an easy thing to get wrong if you're used to byte-based sizing.AL16UTF16 unless you have a concrete, storage-driven reason to reach for UTF8; set it once, deliberately, at creation; and verify it with NLS_DATABASE_PARAMETERS rather than assuming.