•21 min read

Mở rộng DuckDB: Phân tích không gian, tích hợp Parquet & Iceberg từ xa qua HTTPFS

Mở rộng DuckDB: Phân tích không gian, tích hợp Parquet & Iceberg từ xa qua HTTPFS

Công cụ cơ sở dữ liệu phân tích nhúng, nội tiến trình của DuckDB mang lại hiệu suất vượt trội cho việc xử lý dữ liệu cục bộ. Tuy nhiên, sức mạnh thực sự của nó được phát huy thông qua hệ sinh thái tiện ích mở rộng mạnh mẽ. Hướng dẫn này trình bày chi tiết ứng dụng thực tế của ba tiện ích mở rộng quan trọng: spatial cho phân tích không gian địa lý, httpfs để truy vấn trực tiếp các tệp Parquet từ xa qua HTTP(S) và iceberg để kiểm tra siêu dữ liệu bảng Apache Iceberg. Chúng ta sẽ khám phá các nền tảng kiến trúc của chúng, cung cấp các ví dụ mã có thể chạy được, thảo luận về các cân nhắc về hiệu suất và nêu bật các cạm bẫy phổ biến trong sản xuất.

Audio Briefing
0:00 / 0:00

Tổng quan Kiến trúc Tiện ích mở rộng DuckDB

Thiết kế của DuckDB ưu tiên tính mô-đun và khả năng mở rộng. Công cụ cốt lõi cung cấp các khả năng phân tích cú pháp, tối ưu hóa và thực thi SQL cơ bản. Các tiện ích mở rộng bổ sung cho lõi này bằng cách giới thiệu các chức năng mới, bao gồm:

  • Các kiểu dữ liệu mới: Chẳng hạn như GEOMETRY cho dữ liệu không gian.
  • Các hàm mới: Các hàm SQL như ST_Intersects hoặc READ_PARQUET.
  • Các định dạng lưu trữ mới: Hỗ trợ Parquet, CSV, JSON và các định dạng chuyên biệt.
  • Các giao thức mới: Như httpfs cho S3, GCS và truy cập HTTP(S) chung.

Các tiện ích mở rộng được tải động, cho phép người dùng điều chỉnh môi trường DuckDB của họ theo nhu cầu phân tích cụ thể mà không làm phình to công cụ cốt lõi. Mô hình "mang theo chức năng của riêng bạn" này đảm bảo một nền tảng gọn nhẹ, hiệu suất cao trong khi cung cấp các khả năng mở rộng theo yêu cầu.

Quy trình làm việc điển hình để sử dụng một tiện ích mở rộng bao gồm hai lệnh SQL:

  1. INSTALL <extension_name>;: Tải xuống và cài đặt các tệp nhị phân của tiện ích mở rộng. Điều này thường yêu cầu kết nối internet lần đầu tiên.
  2. LOAD <extension_name>;: Tải tiện ích mở rộng đã cài đặt vào phiên DuckDB hiện tại, làm cho các hàm và kiểu của nó có sẵn.

Sự tách biệt này cho phép quản lý hiệu quả và đảm bảo rằng chỉ các thành phần cần thiết mới tiêu thụ tài nguyên.

Advertisement

1. Phân tích không gian với tiện ích mở rộng spatial

Dữ liệu không gian địa lý có mặt ở khắp mọi nơi, từ hậu cần và quy hoạch đô thị đến giám sát môi trường. Tiện ích mở rộng spatial mang các khả năng GIS mạnh mẽ trực tiếp vào DuckDB, cho phép các truy vấn không gian phức tạp trên dữ liệu cục bộ mà không yêu cầu một cơ sở dữ liệu không gian địa lý riêng biệt.

Các khái niệm cốt lõi

Tiện ích mở rộng spatial giới thiệu kiểu dữ liệu GEOMETRY, có thể biểu diễn các điểm, đường, đa giác và đa hình học. Nó hỗ trợ các định dạng và hoạt động dữ liệu không gian địa lý tiêu chuẩn:

  • Well-Known Text (WKT): Một định dạng văn bản dễ đọc để biểu diễn các đối tượng hình học vector. Ví dụ: POINT (10 20), POLYGON ((30 10, 40 40, 20 40, 10 20, 30 10)).
  • Well-Known Binary (WKB): Một định dạng nhị phân cho các đối tượng hình học tương tự, hiệu quả hơn cho việc lưu trữ và truyền tải.
  • GeoJSON: Một định dạng dựa trên JSON để mã hóa các cấu trúc dữ liệu địa lý.

Tiện ích mở rộng cung cấp các hàm để chuyển đổi giữa các định dạng này, tạo hình học và thực hiện các mối quan hệ không gian (ví dụ: giao cắt, chứa, khoảng cách).

Cài đặt và tải

INSTALL spatial;
LOAD spatial;

Ví dụ: Tải GeoJSON và thực hiện các phép giao cắt không gian

Hãy xem xét một kịch bản trong đó chúng ta có một tập dữ liệu các điểm (ví dụ: vị trí cảm biến) và một tập hợp các đa giác (ví dụ: ranh giới hành chính). Chúng ta muốn tìm xem cảm biến nào nằm trong ranh giới nào.

Đầu tiên, hãy tạo một số dữ liệu GeoJSON mẫu để minh họa.

import duckdb
import json

# Sample GeoJSON data
# Polygon 1: A square area
polygon_geojson_1 = {
    "type": "Feature",
    "geometry": {
        "type": "Polygon",
        "coordinates": [[
            [0, 0], [0, 10], [10, 10], [10, 0], [0, 0]
        ]]
    },
    "properties": {"name": "Area A"}
}

# Polygon 2: Another square area, slightly offset
polygon_geojson_2 = {
    "type": "Feature",
    "geometry": {
        "type": "Polygon",
        "coordinates": [[
            [5, 5], [5, 15], [15, 15], [15, 5], [5, 5]
        ]]
    },
    "properties": {"name": "Area B"}
}

# Points: Some inside, some outside, some in overlap
point_geojson_1 = {
    "type": "Feature",
    "geometry": {"type": "Point", "coordinates": [2, 2]},
    "properties": {"sensor_id": "S001"}
}
point_geojson_2 = {
    "type": "Feature",
    "geometry": {"type": "Point", "coordinates": [7, 7]},
    "properties": {"sensor_id": "S002"}
}
point_geojson_3 = {
    "type": "Feature",
    "geometry": {"type": "Point", "coordinates": [12, 12]},
    "properties": {"sensor_id": "S003"}
}
point_geojson_4 = {
    "type": "Feature",
    "geometry": {"type": "Point", "coordinates": [20, 20]},
    "properties": {"sensor_id": "S004"}
}

# Create DuckDB in-memory database
con = duckdb.connect(database=':memory:', read_only=False)

# Install and load spatial extension
con.execute("INSTALL spatial;")
con.execute("LOAD spatial;")

# Create tables and insert data
con.execute("""
CREATE TABLE polygons (
    id INTEGER,
    name VARCHAR,
    geometry GEOMETRY
);
""")

con.execute("""
CREATE TABLE points (
    id INTEGER,
    sensor_id VARCHAR,
    geometry GEOMETRY
);
""")

# Insert polygons
con.execute(f"""
INSERT INTO polygons (id, name, geometry) VALUES
(1, '{polygon_geojson_1['properties']['name']}', ST_GeomFromGeoJSON('{json.dumps(polygon_geojson_1['geometry'])}')),
(2, '{polygon_geojson_2['properties']['name']}', ST_GeomFromGeoJSON('{json.dumps(polygon_geojson_2['geometry'])}'));
""")

# Insert points
con.execute(f"""
INSERT INTO points (id, sensor_id, geometry) VALUES
(1, '{point_geojson_1['properties']['sensor_id']}', ST_GeomFromGeoJSON('{json.dumps(point_geojson_1['geometry'])}')),
(2, '{point_geojson_2['properties']['sensor_id']}', ST_GeomFromGeoJSON('{json.dumps(point_geojson_2['geometry'])}')),
(3, '{point_geojson_3['properties']['sensor_id']}', ST_GeomFromGeoJSON('{json.dumps(point_geojson_3['geometry'])}')),
(4, '{point_geojson_4['properties']['sensor_id']}', ST_GeomFromGeoJSON('{json.dumps(point_geojson_4['geometry'])}'));
""")

# Perform spatial intersection query
print("Sensors intersecting with polygons:")
result = con.execute("""
SELECT
    p.sensor_id,
    poly.name AS polygon_name
FROM
    points AS p,
    polygons AS poly
WHERE
    ST_Intersects(p.geometry, poly.geometry);
""").fetchdf()

print(result)

# Example: Calculate distance between two points
print("\nDistance between S001 and S002:")
distance_result = con.execute("""
SELECT
    ST_Distance(
        (SELECT geometry FROM points WHERE sensor_id = 'S001'),
        (SELECT geometry FROM points WHERE sensor_id = 'S002')
    ) AS distance;
""").fetchdf()
print(distance_result)

con.close()

Giải thích kiến trúc: Hàm ST_GeomFromGeoJSON phân tích chuỗi GeoJSON và chuyển đổi nó thành biểu diễn GEOMETRY nội bộ của DuckDB. Biểu diễn này được tối ưu hóa cho các hoạt động không gian. Hàm ST_Intersects sau đó thực hiện một phép nối không gian, xác định hiệu quả các phần chồng chéo giữa các hình học. Đối với các truy vấn phức tạp liên quan đến nhiều hình học, trình tối ưu hóa truy vấn của DuckDB tận dụng lập chỉ mục không gian (nếu có và được tiện ích mở rộng bật, mặc dù việc tạo chỉ mục không gian rõ ràng như trong PostGIS không phải là tính năng chính của DuckDB; nó dựa vào các tối ưu hóa nội bộ cho các phép nối không gian).

Các cân nhắc về hiệu suất

  • Biểu diễn dữ liệu: Lưu trữ trực tiếp các hình học dưới dạng kiểu GEOMETRY hiệu quả hơn việc phân tích cú pháp các chuỗi WKT/WKB/GeoJSON lặp đi lặp lại.
  • Đơn giản hóa: Để trực quan hóa hoặc phân tích kém chính xác hơn, việc đơn giản hóa các hình học phức tạp bằng cách sử dụng các hàm như ST_Simplify có thể giảm đáng kể thời gian xử lý.
  • Bộ lọc hộp giới hạn: Đối với các tập dữ liệu rất lớn, việc lọc trước bằng cách sử dụng các phép giao cắt hộp giới hạn (ST_Intersects(ST_Envelope(geom1), ST_Envelope(geom2))) có thể nhanh chóng loại bỏ các hình học không chồng chéo trước khi thực hiện các kiểm tra giao cắt chính xác tốn kém hơn.
  • Bộ nhớ: Các hoạt động không gian có thể tốn nhiều bộ nhớ, đặc biệt với các đa giác phức tạp. Đảm bảo đủ bộ nhớ được cấp phát cho DuckDB.

2. HTTPFS Parquet từ xa với tiện ích mở rộng httpfs

Truy cập dữ liệu được lưu trữ từ xa trong bộ lưu trữ đối tượng đám mây (S3, GCS, Azure Blob Storage) hoặc qua HTTP(S) tiêu chuẩn là một yêu cầu cơ bản đối với các kiến trúc dữ liệu hiện đại. Tiện ích mở rộng httpfs cho phép DuckDB truy vấn trực tiếp các tệp Parquet, CSV và JSON từ các nguồn từ xa này mà không yêu cầu tải xuống toàn bộ tệp.

Giải thích kiến trúc

Tiện ích mở rộng httpfs hoạt động bằng cách tận dụng các yêu cầu HTTP Range. Thay vì tải xuống toàn bộ tệp từ xa, DuckDB yêu cầu các phạm vi byte cụ thể tương ứng với các khối dữ liệu hoặc các khối cột được yêu cầu bởi truy vấn. Điều này đặc biệt hiệu quả cho:

  • Cắt cột: Nếu một truy vấn chỉ chọn một vài cột, DuckDB chỉ tìm nạp các phạm vi byte cho các cột cụ thể đó.
  • Đẩy điều kiện: Nếu một mệnh đề WHERE có thể được đánh giá dựa trên siêu dữ liệu hoặc thống kê được nhúng trong tệp Parquet (ví dụ: giá trị min/max cho một cột), DuckDB có thể bỏ qua toàn bộ các nhóm hàng không thỏa mãn điều kiện, tìm nạp ít dữ liệu hơn nữa.

Cách tiếp cận "zero-ETL" này giảm thiểu việc truyền tải mạng, giảm độ trễ và cho phép DuckDB hoạt động như một công cụ phân tích mạnh mẽ trực tiếp trên các hồ dữ liệu.

Cài đặt và tải

INSTALL httpfs;
LOAD httpfs;

Ví dụ: Truy vấn các tệp Parquet từ xa

Chúng ta sẽ truy vấn một tập dữ liệu Parquet có sẵn công khai, chẳng hạn như Dữ liệu ghi lại chuyến đi taxi NYC, thường được lưu trữ trên S3.

import duckdb
import os

# Create DuckDB in-memory database
con = duckdb.connect(database=':memory:', read_only=False)

# Install and load httpfs extension
con.execute("INSTALL httpfs;")
con.execute("LOAD httpfs;")

# Configure S3 credentials if accessing private buckets.
# For public buckets, these are not strictly necessary, but good practice for consistency.
# Replace with your actual credentials or environment variables.
# con.execute("SET s3_access_key_id='YOUR_ACCESS_KEY_ID';")
# con.execute("SET s3_secret_access_key='YOUR_SECRET_ACCESS_KEY';")
# con.execute("SET s3_region='us-east-1';") # Or your bucket's region

# Example: Querying a public Parquet file from S3
# This URL points to a small sample of NYC Yellow Taxi data for 2023-01
s3_parquet_url = "s3://nyc-tlc/trip data/yellow_tripdata_2023-01.parquet"

print(f"Querying remote Parquet file: {s3_parquet_url}")

# Query 1: Count total rows (demonstrates full scan if no pushdown)
print("\nQuery 1: Count total rows")
result_count = con.execute(f"SELECT COUNT(*) FROM '{s3_parquet_url}';").fetchdf()
print(result_count)

# Query 2: Select specific columns and apply a filter (demonstrates column pruning and predicate pushdown)
print("\nQuery 2: Select specific columns and filter by trip distance")
result_filtered = con.execute(f"""
SELECT
    vendor_id,
    tpep_pickup_datetime,
    trip_distance,
    total_amount
FROM
    '{s3_parquet_url}'
WHERE
    trip_distance > 10
LIMIT 10;
""").fetchdf()
print(result_filtered)

# Query 3: Aggregate data (demonstrates more complex processing)
print("\nQuery 3: Average trip distance by vendor")
result_avg_distance = con.execute(f"""
SELECT
    vendor_id,
    AVG(trip_distance) AS avg_distance
FROM
    '{s3_parquet_url}'
GROUP BY
    vendor_id;
""").fetchdf()
print(result_avg_distance)

con.close()

Giải thích kiến trúc: Khi READ_PARQUET('s3://...') được thực thi, tiện ích mở rộng httpfs của DuckDB trước tiên đọc phần cuối và siêu dữ liệu lược đồ của tệp Parquet. Siêu dữ liệu này chứa thông tin về các kiểu cột, ranh giới nhóm hàng và thống kê. Trình tối ưu hóa truy vấn sau đó sử dụng thông tin này để xác định các phạm vi byte nào (tương ứng với các cột và nhóm hàng cụ thể) là cần thiết để thực hiện truy vấn. Chỉ các phạm vi cụ thể này mới được tìm nạp qua HTTP(S), giảm thiểu việc truyền dữ liệu. Ví dụ, trong "Truy vấn 2", DuckDB chỉ tìm nạp các cột vendor_id, tpep_pickup_datetime, trip_distance và total_amount, và có thể bỏ qua các nhóm hàng mà phạm vi min/max của trip_distance không chồng chéo với > 10.

Các cân nhắc về hiệu suất

  • Độ trễ và băng thông mạng: Nút thắt cổ chai chính đối với httpfs là mạng. Độ trễ cao hoặc băng thông thấp đến bộ lưu trữ từ xa sẽ ảnh hưởng trực tiếp đến hiệu suất truy vấn.
  • Gần khu vực: Lưu trữ dữ liệu của bạn trong cùng một khu vực đám mây với phiên bản DuckDB của bạn (hoặc máy đang chạy nó) để giảm thiểu độ trễ mạng.
  • Cắt cột: Luôn chỉ chọn các cột bạn cần (SELECT col1, col2 thay vì SELECT *). Đây là lợi ích hiệu suất đáng kể nhất đối với các bảng rộng.
  • Đẩy điều kiện: Thiết kế các tệp Parquet của bạn với các thống kê thích hợp (ví dụ: giá trị min/max cho các cột được lọc thường xuyên) và sử dụng các mệnh đề WHERE có thể tận dụng các thống kê này.
  • Kích thước tệp Parquet: Mặc dù httpfs xử lý các tệp lớn, nhiều tệp Parquet nhỏ có thể dẫn đến chi phí tăng lên do đọc siêu dữ liệu và yêu cầu HTTP nhiều hơn. Kích thước tệp Parquet tối ưu thường nằm trong khoảng từ 128MB đến 1GB.
  • Bộ nhớ đệm: DuckDB có thể lưu vào bộ nhớ đệm dữ liệu từ xa cục bộ, cải thiện hiệu suất cho các truy vấn lặp lại trên cùng một dữ liệu.

Các vấn đề bảo mật

  • Thông tin xác thực: Đối với các nhóm S3/GCS riêng tư, đảm bảo thông tin xác thực (s3_access_key_id, s3_secret_access_key, s3_region, s3_endpoint, v.v.) được quản lý an toàn. Tránh mã hóa cứng chúng trong môi trường sản xuất. Sử dụng các biến môi trường, vai trò IAM (cho EC2/ECS) hoặc thông tin xác thực tạm thời.
  • Truy cập công khai: Cẩn thận khi cấp quyền truy cập đọc công khai cho các nhóm. Đảm bảo chỉ dữ liệu không nhạy cảm mới được tiết lộ.
  • HTTPS: Luôn sử dụng HTTPS để truy cập từ xa để mã hóa dữ liệu trong quá trình truyền.

3. Tích hợp Iceberg với tiện ích mở rộng iceberg

Apache Iceberg là một định dạng bảng mở được thiết kế cho các bảng phân tích lớn, hiệu suất cao. Nó cung cấp các tính năng như tiến hóa lược đồ, phân vùng ẩn, tiến hóa phân vùng và du hành thời gian. Tiện ích mở rộng iceberg cho DuckDB cho phép bạn kiểm tra và truy vấn siêu dữ liệu bảng Iceberg, và sau đó truy vấn các tệp dữ liệu cơ bản.

Giải thích kiến trúc

Một bảng Iceberg không phải là một tệp duy nhất mà là một tập hợp các tệp được tổ chức bởi siêu dữ liệu. Các thành phần chính bao gồm:

  • Tệp siêu dữ liệu bảng: Trỏ đến ảnh chụp nhanh hiện tại của bảng.
  • Tệp danh sách kê khai: Liệt kê các tệp kê khai cho một ảnh chụp nhanh.
  • Tệp kê khai: Liệt kê các tệp dữ liệu (Parquet, ORC, AVRO) tạo nên một phân vùng hoặc toàn bộ bảng.
  • Tệp dữ liệu: Dữ liệu thực tế, thường ở định dạng Parquet.

Tiện ích mở rộng iceberg của DuckDB chủ yếu tập trung vào việc đọc siêu dữ liệu Iceberg. Khi bạn sử dụng iceberg_scan(), DuckDB phân tích các tệp siêu dữ liệu Iceberg (bắt đầu từ vị trí siêu dữ liệu gốc của bảng) để hiểu lược đồ, phân vùng của bảng và vị trí của các tệp dữ liệu thực tế. Sau đó, nó sử dụng tiện ích mở rộng httpfs (nếu các tệp dữ liệu ở xa) để đọc các tệp dữ liệu này.

Lưu ý quan trọng: Tiện ích mở rộng iceberg của DuckDB hiện chỉ đọc. Nó không thể tạo, sửa đổi hoặc ghi vào các bảng Iceberg. Trường hợp sử dụng chính của nó là để kiểm tra nhanh và truy vấn phân tích các tập dữ liệu Iceberg hiện có.

Cài đặt và tải

INSTALL iceberg;
LOAD iceberg;

Ví dụ: Kiểm tra siêu dữ liệu của bảng Iceberg và truy vấn dữ liệu

Đối với ví dụ này, chúng ta sẽ giả định một bảng Iceberg hiện có được lưu trữ trên S3. Nếu bạn không có, bạn có thể tạo một bảng giả bằng Spark hoặc Flink, hoặc trỏ đến một mẫu Iceberg công khai. Chúng ta sẽ sử dụng một đường dẫn giả định.

import duckdb
import os

# Create DuckDB in-memory database
con = duckdb.connect(database=':memory:', read_only=False)

# Install and load httpfs and iceberg extensions
con.execute("INSTALL httpfs;")
con.execute("LOAD httpfs;")
con.execute("INSTALL iceberg;")
con.execute("LOAD iceberg;")

# Configure S3 credentials if accessing private buckets
# con.execute("SET s3_access_key_id='YOUR_ACCESS_KEY_ID';")
# con.execute("SET s3_secret_access_key='YOUR_SECRET_ACCESS_KEY';")
# con.execute("SET s3_region='us-east-1';")

# Path to the Iceberg table's metadata directory (e.g., s3://your-bucket/your-iceberg-table/metadata)
# Replace with a real Iceberg table path if you have one.
# For demonstration, we'll use a placeholder.
# A real Iceberg table path would look like: s3://bucket/path/to/table
# The iceberg extension expects the path to the table directory, not the metadata directory specifically.
iceberg_table_path = "s3://duckdb-iceberg-sample/nyc_taxi_trips" # Example public Iceberg table

print(f"Accessing Iceberg table at: {iceberg_table_path}")

# Query 1: Inspect Iceberg table schema and metadata
# The iceberg_scan function allows you to query the table directly.
print("\nQuery 1: Inspecting Iceberg table schema and a few rows")
try:
    result_schema = con.execute(f"""
    SELECT *
    FROM iceberg_scan('{iceberg_table_path}')
    LIMIT 5;
    """).fetchdf()
    print(result_schema)
except duckdb.Error as e:
    print(f"Error querying Iceberg table: {e}")
    print("Please ensure the Iceberg table path is correct and accessible.")

# Query 2: Perform an aggregation on the Iceberg table data
print("\nQuery 2: Average trip distance from Iceberg table")
try:
    result_avg_distance_iceberg = con.execute(f"""
    SELECT
        vendor_id,
        AVG(trip_distance) AS avg_distance
    FROM
        iceberg_scan('{iceberg_table_path}')
    GROUP BY
        vendor_id;
    """).fetchdf()
    print(result_avg_distance_iceberg)
except duckdb.Error as e:
    print(f"Error querying Iceberg table: {e}")
    print("Please ensure the Iceberg table path is correct and accessible.")

con.close()

Giải thích kiến trúc: Khi iceberg_scan() được gọi, DuckDB trước tiên định vị thư mục metadata trong iceberg_table_path được chỉ định. Sau đó, nó đọc version-hint.text mới nhất hoặc trực tiếp tệp vX.metadata.json mới nhất để xác định ảnh chụp nhanh hiện tại. Từ ảnh chụp nhanh, nó đọc các tệp danh sách kê khai, đến lượt chúng trỏ đến các tệp kê khai. Cuối cùng, các tệp kê khai cung cấp đường dẫn đến các tệp dữ liệu thực tế (ví dụ: tệp Parquet). DuckDB sau đó sử dụng tiện ích mở rộng httpfs để đọc các tệp dữ liệu riêng lẻ này, áp dụng cắt cột và đẩy điều kiện như được mô tả trong phần httpfs. Việc giải quyết siêu dữ liệu nhiều bước này minh bạch đối với người dùng, người chỉ cần truy vấn hàm iceberg_scan().

Hạn chế và trường hợp sử dụng

  • Chỉ đọc: Hạn chế chính là tiện ích mở rộng iceberg của DuckDB chỉ đọc. Nó không thể được sử dụng để tạo, thêm, cập nhật hoặc xóa dữ liệu trong các bảng Iceberg.
  • Kiểm tra siêu dữ liệu: Tuyệt vời để nhanh chóng hiểu lược đồ, phân vùng và vị trí tệp dữ liệu của bảng Iceberg.
  • Phân tích đặc biệt: Lý tưởng để thực hiện các truy vấn và phân tích đặc biệt trên các tập dữ liệu Iceberg hiện có mà không cần khởi động một công cụ phân tán như Spark.
  • Phát triển/Kiểm thử cục bộ: Hữu ích cho việc phát triển và kiểm thử cục bộ đối với các tập con dữ liệu Iceberg.
Advertisement

Tối ưu hóa hiệu suất & Quản lý bộ nhớ

Hiệu suất của DuckDB phụ thuộc rất nhiều vào việc sử dụng tài nguyên hiệu quả.

  • Giới hạn bộ nhớ: Đặt giới hạn bộ nhớ rõ ràng để ngăn DuckDB tiêu thụ tất cả RAM có sẵn, đặc biệt khi xử lý các tập dữ liệu lớn.
    PRAGMA memory_limit='8GB'; -- Set to 8 Gigabytes
    
  • Số luồng: Kiểm soát số lượng luồng DuckDB sử dụng để xử lý song song.
    PRAGMA threads=4; -- Use 4 threads
    
  • Truy cập bên ngoài: Để httpfs và iceberg truy cập tài nguyên từ xa, quyền truy cập bên ngoài phải được bật.
    SET enable_external_access=true;
    
  • Xử lý theo cột: DuckDB là một cơ sở dữ liệu theo cột. Luôn chỉ chọn các cột bạn cần. Điều này rất quan trọng đối với hiệu suất, đặc biệt với httpfs vì nó giảm thiểu I/O mạng.
  • Đẩy điều kiện: Đảm bảo các mệnh đề WHERE càng chọn lọc càng tốt. Trình tối ưu hóa của DuckDB sẽ đẩy các điều kiện này xuống nguồn dữ liệu (ví dụ: thống kê tệp Parquet) để giảm lượng dữ liệu được đọc.
  • Kiểu dữ liệu: Sử dụng các kiểu dữ liệu thích hợp. Đối với dữ liệu không gian, đảm bảo các hình học được lưu trữ dưới dạng kiểu GEOMETRY.
  • Lập chỉ mục không gian (Ngầm định): Mặc dù DuckDB không có cú pháp CREATE SPATIAL INDEX rõ ràng như PostGIS, trình tối ưu hóa truy vấn của nó được thiết kế để xử lý hiệu quả các phép nối không gian. Đối với các tập dữ liệu không gian rất lớn, hãy cân nhắc xử lý trước để đơn giản hóa hình học hoặc sử dụng bộ lọc hộp giới hạn.
  • Tối ưu hóa tệp Parquet: Đối với httpfs và iceberg, đảm bảo các tệp Parquet cơ bản được tối ưu hóa tốt:
    • Kích thước nhóm hàng: Nhắm mục tiêu các nhóm hàng có kích thước 128MB-1GB.
    • Thống kê cột: Đảm bảo có thống kê (min/max) cho các cột được sử dụng trong các mệnh đề WHERE.
    • Nén: Sử dụng nén hiệu quả (ví dụ: Snappy, ZSTD).

Các lỗi thường gặp & Cạm bẫy trong sản xuất

  1. Không tìm thấy/Tải tiện ích mở rộng:

    • Vấn đề: Error: Catalog Error: Function with name 'ST_Intersects' does not exist.
    • Nguyên nhân: Tiện ích mở rộng chưa được INSTALL hoặc LOAD trong phiên hiện tại. INSTALL tải xuống, LOAD kích hoạt.
    • Khắc phục: Chạy INSTALL <extension_name>; và LOAD <extension_name>; khi bắt đầu phiên của bạn. Đảm bảo kết nối internet trong quá trình INSTALL.
  2. Thông tin xác thực và quyền HTTPFS:

    • Vấn đề: Error: IO Error: S3 Error [AWS_ERROR_S3_ACCESS_DENIED] hoặc [AWS_ERROR_S3_INVALID_ACCESS_KEY_ID]
    • Nguyên nhân: Thông tin xác thực S3/GCS không chính xác, thiếu lệnh SET cho s3_access_key_id, s3_secret_access_key, s3_region, hoặc quyền IAM không đủ trên nhóm/đối tượng.
    • Khắc phục: Xác minh thông tin xác thực. Đảm bảo vai trò/người dùng IAM có quyền s3:GetObject và s3:ListBucket. Đối với GCS, đảm bảo gcs_access_key_id và gcs_secret_access_key được đặt, hoặc sử dụng thông tin xác thực tài khoản dịch vụ.
  3. Độ trễ mạng và chi phí egress:

    • Vấn đề: Các truy vấn đối với dữ liệu từ xa chậm, hoặc hóa đơn đám mây cao bất ngờ.
    • Nguyên nhân: Độ trễ mạng cao giữa DuckDB và bộ lưu trữ từ xa, hoặc truyền dữ liệu quá mức (egress) do các truy vấn không hiệu quả.
    • Khắc phục: Đặt DuckDB cùng vị trí với dữ liệu của bạn (cùng khu vực đám mây). Tối ưu hóa các truy vấn bằng cách cắt cột (SELECT specific_cols) và đẩy điều kiện (WHERE filter_conditions). Giám sát chi phí egress.
  4. Hết bộ nhớ:

    • Vấn đề: Error: Out of Memory: Failed to allocate X bytes
    • Nguyên nhân: DuckDB cố gắng tải quá nhiều dữ liệu vào bộ nhớ cho các hoạt động phức tạp (ví dụ: các phép nối lớn, các hoạt động không gian phức tạp, hoặc đọc các tệp Parquet rất lớn mà không có đủ bộ lọc).
    • Khắc phục: Đặt PRAGMA memory_limit='XGB';. Tối ưu hóa các truy vấn để giảm kích thước kết quả trung gian. Đối với httpfs, đảm bảo đẩy điều kiện và cắt cột mạnh mẽ. Cân nhắc xử lý dữ liệu theo từng khối nếu có thể.
  5. Không khớp kiểu dữ liệu (Không gian):

    • Vấn đề: Error: Conversion Error: Could not convert string '...' to GEOMETRY.
    • Nguyên nhân: Chuỗi đầu vào cho ST_GeomFromWKT, `ST_
Share this article:

Stay Updated

Get the latest posts delivered straight to your inbox.

Free Developer Utilities

Free In-Browser Developer Tools

Clean AI CLI logs, build cron expressions, decode JWTs, and calculate chmod permissions offline.

Explore Tools
Advertisement