AnalyticDB for MySQL memungkinkan Anda mengimpor data eksternal melalui tabel eksternal. Topik ini menjelaskan cara menggunakan tabel eksternal untuk mengimpor data dari OSS ke kluster AnalyticDB for MySQL.
Prasyarat
Kluster AnalyticDB for MySQL dan bucket OSS berada di wilayah yang sama. Untuk informasi selengkapnya, lihat Aktifkan OSS.
Akses Elastic Network Interface (ENI) diaktifkan untuk kluster AnalyticDB for MySQL Edisi Data Lakehouse.
PentingMasuk ke Konsol AnalyticDB for MySQL. Pada halaman Cluster Information, di bagian Network Information, aktifkan sakelar jaringan Elastic Network Interface (ENI).
Mengaktifkan atau menonaktifkan jaringan ENI akan mengganggu koneksi database selama sekitar 2 menit. Selama periode ini, Anda tidak dapat membaca atau menulis data. Oleh karena itu, evaluasi dampaknya secara hati-hati sebelum mengaktifkan atau menonaktifkan jaringan ENI.
Persiapan data
Dalam contoh ini, file data person.csv diunggah ke direktori testBucketName/adb/dt=2023-06-15 di OSS. Baris baru digunakan sebagai pemisah baris, sedangkan koma (,) digunakan sebagai pemisah kolom. Berikut adalah data sampel dalam file person.csv:
1,james,10,2023-06-15
2,bond,20,2023-06-15
3,jack,30,2023-06-15
4,lucy,40,2023-06-15 Prosedur
Edisi Perusahaan, Edisi Dasar, dan Edisi Data Lakehouse
Buka editor SQL.
Masuk ke Konsol AnalyticDB for MySQL. Di pojok kiri atas konsol, pilih wilayah. Pada panel navigasi sebelah kiri, klik Clusters, lalu temukan kluster yang ingin Anda kelola dan klik ID-nya.
Pada panel navigasi sebelah kiri, klik .
Impor data.
Anda dapat mengimpor data menggunakan metode impor reguler (default) atau metode impor elastis. Metode impor reguler membaca data sumber pada node komputasi dan membuat indeks pada node penyimpanan, sehingga mengonsumsi sumber daya komputasi dan penyimpanan. Metode impor elastis membaca data sumber dan membuat indeks dalam Pekerjaan Spark arsitektur tanpa server, sehingga mengonsumsi sumber daya dari kelompok sumber daya jenis Pekerjaan. Metode impor elastis hanya didukung pada kluster Edisi Perusahaan, Edisi Dasar, dan Edisi Data Lakehouse yang menjalankan Milvus versi 3.1.10.0 atau lebih baru serta memiliki kelompok sumber daya jenis Pekerjaan. Untuk informasi selengkapnya, lihat Metode impor data.
Impor reguler
Buat basis data eksternal.
CREATE EXTERNAL DATABASE adb_external_db;Buat tabel eksternal dengan menggunakan pernyataan CREATE EXTERNAL TABLE untuk membuat tabel eksternal OSS di basis data adb_external_db. Dalam contoh ini, tabel eksternal diberi nama
adb_external_db.person.CatatanTabel eksternal AnalyticDB for MySQL harus memiliki nama bidang, jumlah bidang, urutan bidang, dan tipe bidang yang sama dengan data sumber dalam file OSS.
Untuk informasi selengkapnya tentang sintaks pembuatan tabel eksternal OSS, lihat CREATE EXTERNAL TABLE.
Kueri data.
Setelah tabel dibuat, Anda dapat mengkueri data di OSS dengan menjalankan pernyataan SELECT di AnalyticDB for MySQL.
SELECT * FROM adb_external_db.person;Hasil berikut dikembalikan:
+------+-------+------+-----------+ | id | name | age | dt | +------+-------+------+-----------+ | 1 | james | 10 |2023-06-15 | | 2 | bond | 20 |2023-06-15 | | 3 | jack | 30 |2023-06-15 | | 4 | lucy | 40 |2023-06-15 | +------+-------+------+-----------+Buat basis data di AnalyticDB for MySQL. Jika basis data sudah ada, lewati langkah ini. Contoh pernyataannya sebagai berikut:
CREATE DATABASE adb_demo;Buat tabel di AnalyticDB for MySQL untuk menyimpan data yang diimpor dari OSS. Contoh pernyataannya sebagai berikut:
CatatanTabel internal yang Anda buat harus memiliki nama bidang, jumlah bidang, urutan bidang, dan tipe bidang yang sama dengan tabel eksternal.
CREATE TABLE IF NOT EXISTS adb_demo.adb_import_test( id INT, name VARCHAR(1023), age INT, dt VARCHAR(1023) ) DISTRIBUTED BY HASH(id);Impor data ke dalam tabel.
Metode 1: Gunakan pernyataan
INSERT INTOuntuk mengimpor data. Jika terdapat nilai kunci primer duplikat, data baru akan diabaikan. Ini setara dengan menggunakanINSERT IGNORE INTO. Untuk informasi selengkapnya, lihat INSERT INTO.INSERT INTO adb_demo.adb_import_test SELECT * FROM adb_external_db.person;Metode 2: Gunakan pernyataan
INSERT OVERWRITE INTOuntuk mengimpor data secara sinkron. Metode ini akan menimpa data yang ada di tabel.INSERT OVERWRITE INTO adb_demo.adb_import_test SELECT * FROM adb_external_db.person;Metode 3: Gunakan pernyataan
INSERT OVERWRITE INTOuntuk mengimpor data secara asinkron. Untuk informasi selengkapnya, lihat Penulisan asinkron.SUBMIT JOB INSERT OVERWRITE adb_demo.adb_import_test SELECT * FROM adb_external_db.person;
Impor elastis
Buat basis data. Jika basis data tersebut sudah ada, lewati langkah ini. Pernyataan berikut merupakan contohnya:
CREATE DATABASE adb_demo;Buat tabel eksternal.
CatatanNama bidang, jumlah bidang, urutan bidang, dan tipe bidang pada tabel eksternal AnalyticDB for MySQL harus sesuai dengan data sumber dalam file OSS.
Impor elastis hanya mendukung pembuatan tabel eksternal melalui pernyataan
CREATE TABLE.
CREATE TABLE oss_import_test_external_table ( id INT(1023), name VARCHAR(1023), age INT, dt VARCHAR(1023) ) ENGINE='OSS' TABLE_PROPERTIES='{ "endpoint":"oss-cn-hangzhou-internal.aliyuncs.com", "url":"oss://testBucketName/adb/dt=2023-06-15/person.csv", "accessid":"accesskey_id", "accesskey":"accesskey_secret", "delimiter":"," }';PentingSaat membuat tabel eksternal, parameter
TABLE_PROPERTIESyang didukung bervariasi tergantung pada format file, seperti CSV, Parquet, atau ORC:Format CSV: Hanya parameter
endpoint,url,accessid,accesskey,format,delimiter,null_value, danpartition_columnyang didukung.Format Parquet: Hanya parameter
endpoint,url,accessid,accesskey,format, danpartition_columnyang didukung.Format ORC: Hanya parameter
endpoint,url,accessid,accesskey,format, danpartition_columnyang didukung.
Untuk informasi selengkapnya mengenai parameter yang dapat dikonfigurasi untuk tabel eksternal beserta deskripsinya, lihat Tabel eksternal OSS non-partisi dan Tabel eksternal OSS berpartisi.
Kueri data.
Setelah tabel dibuat, Anda dapat mengkueri data dari OSS dengan menjalankan pernyataan SELECT di AnalyticDB for MySQL.
SELECT * FROM oss_import_test_external_table;Hasil berikut dikembalikan:
+------+-------+------+-----------+ | id | name | age | dt | +------+-------+------+-----------+ | 1 | james | 10 |2023-06-15 | | 2 | bond | 20 |2023-06-15 | | 3 | jack | 30 |2023-06-15 | | 4 | lucy | 40 |2023-06-15 | +------+-------+------+-----------+ 4 rows in set (0.35 sec)Buat tabel di AnalyticDB for MySQL untuk menyimpan data yang diimpor dari OSS. Pernyataan berikut merupakan contohnya:
CatatanTabel internal yang Anda buat harus memiliki nama bidang, jumlah bidang, urutan bidang, dan tipe bidang yang sama dengan tabel eksternal.
CREATE TABLE adb_import_test ( id INT, name VARCHAR(1023), age INT, dt VARCHAR(1023) ) DISTRIBUTED BY HASH(id);Impor data.
PentingImpor elastis hanya mendukung pengimporan data menggunakan pernyataan
INSERT OVERWRITE INTO.Metode 1: Jalankan pernyataan INSERT OVERWRITE INTO untuk mengimpor data secara elastis. Pernyataan ini akan menimpa data yang ada di tabel. Contohnya sebagai berikut:
/+*elastic_load=true, elastic_load_configs=[adb.load.resource.group.name=resource_group]*/ INSERT OVERWRITE INTO adb_demo.adb_import_test SELECT * FROM adb_demo.oss_import_test_external_table;
Metode 2: Jalankan pernyataan INSERT OVERWRITE INTO secara asinkron untuk mengimpor data secara elastis. Anda dapat menggunakan pernyataan
SUBMIT JOBguna mengirimkan tugas asinkron yang dijadwalkan di latar belakang./*+elastic_load=true, elastic_load_configs=[adb.load.resource.group.name=resource_group]*/ SUBMIT JOB INSERT OVERWRITE INTO adb_demo.adb_import_test SELECT * FROM adb_demo.oss_import_test_external_table;PentingAntrian prioritas tidak dapat dikonfigurasi saat mengirimkan tugas impor elastis secara asinkron.
Hasil berikut dikembalikan:
+---------------------------------------+ | job_id | +---------------------------------------+ | 202308151719510210170190********** |
Setelah mengirimkan pekerjaan asinkron menggunakan
SUBMIT JOB, hasil yang dikembalikan hanya menunjukkan bahwa pekerjaan berhasil dikirim. Anda dapat menggunakan job_id untuk menghentikan pekerjaan asinkron atau mengkueri statusnya guna memverifikasi apakah pekerjaan telah berhasil dieksekusi. Untuk informasi selengkapnya, lihat Kirimkan pekerjaan impor asinkron.Parameter petunjuk:
elastic_load: menentukan apakah akan menggunakan impor elastis. Nilai yang valid: true dan false. Nilai default: false.
None
Parameter
Wajib
Deskripsi
adb.load.resource.group.name
Ya
Nama kelompok sumber daya pekerjaan yang menjalankan pekerjaan impor elastis.
adb.load.job.max.acu
Tidak
Jumlah maksimum sumber daya untuk pekerjaan impor elastis. Satuan: unit komputasi AnalyticDB (ACU). Nilai minimum: 5 ACU. Nilai default: jumlah shard ditambah 1.
Jalankan pernyataan berikut untuk mengkueri jumlah shard di kluster:
SELECT count(1) FROM information_schema.kepler_meta_shards;spark.driver.resourceSpec
Tidak
Tipe sumber daya driver Spark. Nilai default: kecil. Untuk informasi tentang nilai yang valid, lihat kolom Tipe dalam tabel "Parameter konfigurasi aplikasi Spark".
spark.executor.resourceSpec
Tidak
Tipe sumber daya executor Spark. Nilai default: Tingkat Tinggi. Untuk informasi tentang nilai yang valid, lihat kolom Tipe dalam tabel "Parameter konfigurasi aplikasi Spark".
spark.adb.executorDiskSize
Tidak
Kapasitas disk executor Spark. Nilai yang valid: (0,100]. Satuan: GiB. Nilai default: 10 GiB. Untuk informasi selengkapnya, lihat bagian "Tentukan sumber daya driver dan executor" dalam topik parameter konfigurasi Conf.
(Opsional) Periksa apakah tugas impor yang dikirimkan merupakan tugas impor elastis.
SELECT job_name, (job_type = 3) AS is_elastic_load FROM INFORMATION_SCHEMA.kepler_meta_async_jobs where job_name = "2023081818010602101701907303151******";Hasil berikut akan dikembalikan:
+---------------------------------------+------------------+ | job_name | is_elastic_load | +---------------------------------------+------------------+ | 20230815171951021017019072*********** | 1 | +---------------------------------------+------------------+Jika nilai
is_elastic_loadadalah 1, tugas impor tersebut merupakan tugas impor elastis. Jika nilainya 0, tugas impor tersebut merupakan tugas impor reguler.
Edisi Data Lakehouse
Sambungkan ke kluster dan buat basis data.
CREATE DATABASE adb_demo;Buat tabel eksternal menggunakan sintaks CREATE TABLE untuk membuat tabel eksternal OSS dalam format CSV, Parquet, atau ORC. Untuk informasi selengkapnya mengenai sintaks tersebut, lihat Sintaks tabel eksternal OSS.
Contoh berikut menggunakan tabel eksternal non-partisi dalam format CSV.
CREATE TABLE IF NOT EXISTS oss_import_test_external_table ( id INT, name VARCHAR(1023), age INT, dt VARCHAR(1023) ) ENGINE='OSS' TABLE_PROPERTIES='{ "endpoint":"oss-cn-hangzhou-internal.aliyuncs.com", "url":"oss://testBucketname/adb/dt=2023-06-15/person.csv", "accessid":"accesskey_id", "accesskey":"accesskey_secret", "delimiter":",", "skip_header_line_count":0, "charset":"utf-8" }';Kueri data dari tabel eksternal
oss_import_test_external_table.CatatanMengkueri tabel eksternal dengan volume data besar dalam format CSV, Parquet, atau ORC dapat menyebabkan overhead kinerja tinggi. Untuk meningkatkan efisiensi kueri, impor data dari tabel eksternal OSS ke AnalyticDB for MySQL, seperti dijelaskan dalam langkah-langkah berikut.
SELECT * FROM oss_import_test_external_table;Buat tabel di AnalyticDB for MySQL untuk menyimpan data yang diimpor dari tabel eksternal OSS.
CREATE TABLE IF NOT EXISTS adb_oss_import_test ( id INT, name VARCHAR(1023), age INT, dt VARCHAR(1023) ) DISTRIBUTED BY HASH(id);Jalankan pernyataan INSERT untuk mengimpor data dari tabel eksternal OSS ke AnalyticDB for MySQL.
PentingPernyataan
INSERT INTOdanINSERT OVERWRITE SELECTsecara default mengimpor data secara sinkron. Proses ini memerlukan koneksi jangka panjang antara klien dan server AnalyticDB for MySQL. Jika Anda mengimpor data dalam jumlah besar—misalnya ratusan gigabyte—koneksi dapat terputus akibat masalah jaringan, sehingga menyebabkan kegagalan impor data. Oleh karena itu, untuk volume data besar, kami menyarankan penggunaanSUBMIT JOB INSERT OVERWRITE SELECTguna mengimpor data secara asinkron.Metode 1: Jalankan pernyataan
INSERT INTOuntuk mengimpor data. Jika terdapat kunci primer duplikat, operasi penulisan saat ini diabaikan dan data tidak diperbarui. Ini setara denganINSERT IGNORE INTO. Untuk informasi selengkapnya, lihat INSERT INTO. Contoh pernyataannya sebagai berikut:INSERT INTO adb_oss_import_test SELECT * FROM oss_import_test_external_table;Metode 2: Jalankan pernyataan INSERT OVERWRITE untuk mengimpor data. Metode ini akan menimpa data yang ada di tabel. Contoh pernyataannya sebagai berikut:
INSERT OVERWRITE adb_oss_import_test SELECT * FROM oss_import_test_external_table;Metode 3: Jalankan pernyataan
INSERT OVERWRITEsecara asinkron untuk mengimpor data. Anda dapat menggunakanSUBMIT JOBuntuk mengirimkan tugas asinkron yang dijadwalkan di latar belakang. Untuk mempercepat proses penulisan, tambahkan petunjuk (/*+ direct_batch_load=true*/) ke dalam tugas tersebut. Untuk informasi selengkapnya, lihat Penulisan asinkron. Contoh pernyataannya sebagai berikut:SUBMIT JOB INSERT OVERWRITE adb_oss_import_test SELECT * FROM oss_import_test_external_table;Hasil berikut dikembalikan:
+---------------------------------------+ | job_id | +---------------------------------------+ | 2020112122202917203100908203303****** |Untuk informasi lebih lanjut tentang cara mengirimkan tugas secara asinkron, lihat Kirimkan pekerjaan impor asinkron.
Sintaks tabel eksternal OSS
Edisi Perusahaan, Edisi Dasar, dan Edisi Data Lakehouse
Untuk informasi selengkapnya mengenai sintaks dan deskripsi tabel eksternal OSS di Edisi Perusahaan, Edisi Dasar, dan Edisi Data Lakehouse, lihat Tabel eksternal OSS.
Edisi Data Lakehouse
Tabel eksternal OSS non-partisi
CREATE TABLE [IF NOT EXISTS] table_name
(column_name column_type[, …])
ENGINE='OSS'
TABLE_PROPERTIES='{
"endpoint":"endpoint",
"url":"OSS_LOCATION",
"accessid":"accesskey_id",
"accesskey":"accesskey_secret",
"format":"csv|orc|parquet|text
"delimiter|field_delimiter":";",
"skip_header_line_count":1,
"charset":"utf-8"
}';
Jenis Tampilan | Parameter | Wajib | Deskripsi |
Tabel eksternal dalam format CSV, Parquet, dan ORC | ENGINE='OSS' | Ya | Mesin tabel. Tetapkan nilainya ke OSS. |
endpoint | Endpoint bucket OSS. Saat ini, AnalyticDB for MySQL hanya dapat mengakses OSS melalui VPC. Catatan Anda dapat masuk ke Konsol OSS, klik bucket target, dan lihat Endpoint di halaman Overview bucket. | ||
url | Jalur file atau direktori OSS.
| ||
accessid | ID AccessKey dari akun Alibaba Cloud atau pengguna Resource Access Management (RAM) dengan izin manajemen OSS. Untuk informasi tentang cara mendapatkan ID AccessKey, lihat Akun dan izin. | ||
accesskey | Rahasia AccessKey dari akun Alibaba Cloud atau pengguna RAM dengan izin manajemen OSS. Untuk mendapatkan rahasia AccessKey, lihat Akun dan izin. | ||
format | Wajib bersyarat | Format file data.
| |
Tabel eksternal dalam format CSV dan Text | delimiter|field_delimiter | Ya | Pemisah kolom file data.
|
Tabel eksternal dalam format CSV | null_value | Tidak | Menentukan nilai Penting Parameter ini hanya didukung untuk kluster versi Milvus 3.1.4.2 atau lebih baru. |
ossnull | Aturan yang digunakan untuk menentukan nilai
Catatan Contoh-contoh di atas mengasumsikan bahwa | ||
skip_header_line_count | Jumlah baris header yang dilewati di awal file data selama impor data. Jika baris pertama file CSV adalah header tabel, Anda dapat menyetel parameter ini ke 1 untuk melewatkan baris header selama impor data. Nilai default: 0. Nilai ini menunjukkan bahwa tidak ada baris yang dilewati. | ||
oss_ignore_quote_and_escape | Menentukan apakah tanda kutip dan karakter escape dalam nilai bidang akan diabaikan. Nilai default: false. Nilai ini menunjukkan bahwa tanda kutip dan karakter escape tidak diabaikan. Penting Parameter ini hanya didukung untuk kluster versi Milvus 3.1.4.2 atau lebih baru. | ||
charset | Set karakter tabel eksternal OSS. Nilai yang valid:
Penting Parameter ini hanya didukung untuk kluster versi Milvus 3.1.10.4 atau lebih baru. |
Nama kolom dalam pernyataan `CREATE TABLE` untuk tabel eksternal harus identik dengan nama kolom dalam file Parquet atau ORC, meskipun tidak peka terhadap huruf besar/kecil. Urutan kolom juga harus sama.
Saat membuat tabel eksternal, Anda hanya dapat memilih beberapa kolom dari file Parquet atau ORC sebagai kolom dalam tabel eksternal. Kolom yang tidak dipilih tidak akan diimpor.
Jika pernyataan `CREATE TABLE` untuk tabel eksternal mencakup kolom yang tidak ada dalam file Parquet atau ORC, kueri terhadap kolom tersebut akan mengembalikan nilai NULL.
AnalyticDB for MySQL mendukung pembacaan dan penulisan file teks Hive menggunakan tabel eksternal dalam format CSV di OSS. Pernyataan berikut dapat digunakan untuk membuat tabel eksternal:
CREATE TABLE adb_csv_hive_format_oss (
a tinyint,
b smallint,
c int,
d bigint,
e boolean,
f float,
g double,
h varchar,
i varchar, -- binary
j timestamp,
k DECIMAL(10, 4),
l varchar, -- char(10)
m varchar, -- varchar(100)
n date
) ENGINE = 'OSS' TABLE_PROPERTIES='{
"format": "csv",
"endpoint":"oss-cn-hangzhou-internal.aliyuncs.com",
"accessid":"accesskey_id",
"accesskey":"accesskey_secret",
"url":"oss://testBucketname/adb_data/",
"delimiter": "\\1",
"null_value": "\\\\N",
"oss_ignore_quote_and_escape": "true",
"ossnull": 2
}';
Perhatikan hal-hal berikut saat membuat tabel eksternal OSS dalam format CSV untuk membaca file teks Hive:
Pemisah kolom default untuk file teks Hive adalah
\1. Untuk membaca dan menulis file teks Hive menggunakan tabel eksternal OSS dalam format CSV, Anda harus melakukan escape delimiter tersebut menjadi\\1saat mengonfigurasi parameterdelimiter.Nilai
NULLdefault untuk file teks Hive adalah\N. Untuk membaca atau menulis file teks Hive menggunakan tabel eksternal dalam format CSV di OSS, Anda harus menyetel parameternull_valuedan melakukan escape nilainya menjadi\\\\N.Tipe data dasar Hive lainnya, seperti
BOOLEAN, dipetakan langsung ke tipe data AnalyticDB for MySQL, sedangkan tipeBINARY,CHAR(n), danVARCHAR(n)semuanya dipetakan ke tipe AnalyticDB for MySQLVARCHAR.
Lampiran: Pemetaan tipe data
Tipe data yang Anda tentukan saat membuat tabel harus konsisten dengan pemetaan dalam tabel berikut. Untuk tipe
DECIMAL, presisi juga harus konsisten.Tabel eksternal dalam format Parquet tidak mendukung tipe
STRUCT. Jika Anda menggunakan tipe ini, pembuatan tabel akan gagal.Tabel eksternal dalam format ORC tidak mendukung tipe kompleks seperti
LIST,STRUCT, atauUNION. Jika Anda menggunakan tipe-tipe ini, pembuatan tabel akan gagal. Anda dapat membuat tabel eksternal ORC yang berisi kolom bertipeMAP, tetapi kueri pada tabel tersebut akan gagal.
Pemetaan tipe data file Parquet dan AnalyticDB for MySQL
Tipe data primitif Parquet | Parquet logicalType | AnalyticDB for MySQL tipe data |
BOOLEAN | Tidak ada | BOOLEAN |
INT32 | INT_8 | TINYINT |
INT32 | INT_16 | SMALLINT |
INT32 | Tidak ada | INT atau INTEGER |
INT64 | Tidak ada | BIGINT |
FLOAT | Tidak ada | FLOAT |
DOUBLE | Tidak ada | DOUBLE |
| DECIMAL | DECIMAL |
BINARY | UTF-8 |
|
INT32 | DATE | DATE |
INT64 | TIMESTAMP_MILLIS | TIMESTAMP atau DATETIME |
INT96 | Tidak ada | TIMESTAMP atau DATETIME |
Pemetaan tipe data file ORC dan AnalyticDB for MySQL
Tipe data file ORC | Tipe data AnalyticDB for MySQL |
BOOLEAN | BOOLEAN |
BYTE | TINYINT |
SHORT | SMALLINT |
INT | INT atau INTEGER |
LONG | BIGINT |
DECIMAL | DECIMAL |
FLOAT | FLOAT |
DOUBLE | DOUBLE |
|
|
TIMESTAMP | TIMESTAMP atau DATETIME |
DATE | DATE |
Pemetaan tipe data file Paimon dan AnalyticDB for MySQL
Tipe data file Paimon | Tipe data AnalyticDB for MySQL |
CHAR | VARCHAR |
VARCHAR | VARCHAR |
BOOLEAN | BOOLEAN |
BINARY | VARBINARY |
VARBINARY | VARBINARY |
DECIMAL | DECIMAL |
TINYINT | TINYINT |
SMALLINT | SMALLINT |
INT | INTEGER |
BIGINT | BIGINT |
FLOAT | REAL |
DOUBLE | DOUBLE |
DATE | DATE |
TIME | Tidak didukung |
TIMESTAMP | TIMESTAMP |
LocalZonedTIMESTAMP | TIMESTAMP (informasi zona waktu lokal diabaikan) |
ARRAY | ARRAY |
MAP | MAP |
ROW | ROW |