返回文章列表

MySQL資料型別與表格連線技術

深入探討MySQL資料型別的選擇策略與表格連線技術,涵蓋數值型別、字串型別、日期時間型別、二進位型別、JSON型別、空間資料型別,以及各種JOIN操作的效能優化實務

資料庫 SQL

MySQL作為全球最受歡迎的開源關聯式資料庫管理系統,其資料型別系統的豐富程度與表格連線機制的靈活性是其核心優勢所在。正確選擇資料型別不僅影響資料的儲存效率與查詢效能,更關係到資料的完整性與應用程式的正確運作。表格連線則是關聯式資料庫的核心操作,它使我們能夠將分散在多個正規化表格中的相關資料整合在一起,提供完整的資訊視圖。本文將深入探討MySQL提供的各種資料型別,包括數值型別、字串型別、日期時間型別、二進位型別、JSON型別,以及空間資料型別,並詳細解析各種表格連線操作的語法、應用場景與效能優化策略。

資料型別的選擇是資料庫設計的基礎決策之一。一個精心選擇的資料型別可以最小化儲存空間的使用、提升查詢效能、確保資料的有效性,並減少應用程式的複雜度。相反地,不恰當的資料型別選擇可能導致空間浪費、效能下降、資料精度損失,甚至功能錯誤。MySQL提供了豐富的資料型別選項,每種型別都有其特定的用途與限制。理解這些型別的特性並根據實際需求進行選擇,是每位資料庫開發者必須掌握的技能。

@startuml
!define PLANTUML_FORMAT svg
!theme _none_

skinparam dpi auto
skinparam shadowing false
skinparam linetype ortho
skinparam roundcorner 5
skinparam defaultFontName "Microsoft JhengHei UI"
skinparam defaultFontSize 16
skinparam minClassWidth 100

package "MySQL資料型別系統" {
    rectangle "數值型別" as numeric {
        card "整數: TINYINT, SMALLINT, MEDIUMINT, INT, BIGINT" as int
        card "浮點數: FLOAT, DOUBLE" as float
        card "定點數: DECIMAL" as decimal
        card "位元: BIT" as bit
    }

    rectangle "字串型別" as string {
        card "定長: CHAR" as char
        card "變長: VARCHAR" as varchar
        card "文字: TEXT, MEDIUMTEXT, LONGTEXT" as text
        card "枚舉: ENUM, SET" as enum
    }

    rectangle "日期時間型別" as datetime {
        card "DATE, TIME" as date
        card "DATETIME, TIMESTAMP" as ts
        card "YEAR" as year
    }

    rectangle "二進位型別" as binary {
        card "BINARY, VARBINARY" as bin
        card "BLOB, MEDIUMBLOB, LONGBLOB" as blob
    }

    rectangle "特殊型別" as special {
        card "JSON" as json
        card "空間資料: POINT, POLYGON" as spatial
    }
}

numeric --> string : 型別轉換
string --> datetime : 格式解析
binary --> blob : 大小擴展
json --> string : 文字表示

@enduml

數值型別是資料庫中最常用的型別之一,用於儲存整數與小數。MySQL的整數型別包括TINYINT、SMALLINT、MEDIUMINT、INT與BIGINT,它們的儲存空間從1位元組到8位元組不等,對應的數值範圍也隨之擴大。選擇整數型別時,應當根據預期的數值範圍選擇最小且足夠的型別,這樣可以最大化儲存效率並提升查詢效能。對於永遠不會為負數的值,如ID、數量等,可以使用UNSIGNED關鍵字將數值範圍向正數方向擴展一倍。浮點數型別FLOAT與DOUBLE用於儲存近似數值,適用於科學計算等精度要求不嚴格的場景。定點數型別DECIMAL則儲存精確數值,是金融應用中貨幣金額的首選型別。

-- 數值型別使用範例
-- 展示各種數值型別的定義與應用場景

-- 建立商品資料表
-- 展示不同數值型別的適用場景
CREATE TABLE products (
    -- 商品ID使用INT UNSIGNED
    -- 範圍0到4,294,967,295,足夠大多數應用
    product_id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,

    -- 庫存數量使用SMALLINT UNSIGNED
    -- 範圍0到65,535,適合一般庫存管理
    stock_quantity SMALLINT UNSIGNED NOT NULL DEFAULT 0,

    -- 重量使用DECIMAL確保精確度
    -- (10,3)表示總共10位數,小數點後3位
    -- 可儲存-9999999.999到9999999.999
    weight_kg DECIMAL(10, 3),

    -- 價格使用DECIMAL確保金額精確
    -- (12,2)適合大多數貨幣金額
    unit_price DECIMAL(12, 2) NOT NULL,

    -- 折扣率使用DECIMAL
    -- (5,4)允許如0.1234這樣的精確百分比
    discount_rate DECIMAL(5, 4) DEFAULT 0.0000,

    -- 評分使用TINYINT UNSIGNED
    -- 範圍0到255,5星評分系統綽綽有餘
    rating TINYINT UNSIGNED DEFAULT 0,

    -- 瀏覽次數使用BIGINT UNSIGNED
    -- 處理極大數值,如熱門商品的瀏覽量
    view_count BIGINT UNSIGNED DEFAULT 0,

    -- 是否上架使用BOOLEAN
    -- 實際上是TINYINT(1)的別名
    is_active BOOLEAN DEFAULT TRUE,

    -- 建立時間
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,

    -- 索引
    INDEX idx_price (unit_price),
    INDEX idx_stock (stock_quantity),
    INDEX idx_active (is_active)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- 插入測試資料
INSERT INTO products (stock_quantity, weight_kg, unit_price, discount_rate, rating)
VALUES
    (100, 0.500, 299.00, 0.0850, 5),
    (50, 1.250, 599.00, 0.1000, 4),
    (200, 0.125, 99.50, 0.0500, 5);

-- 查詢帶折扣的價格
-- 展示DECIMAL的精確計算
SELECT
    product_id,
    unit_price AS 原價,
    discount_rate AS 折扣率,
    ROUND(unit_price * (1 - discount_rate), 2) AS 折扣後價格
FROM products
WHERE is_active = TRUE;

字串型別用於儲存文字資料,MySQL提供了多種選項以適應不同的需求。CHAR型別用於儲存固定長度的字串,適合儲存長度固定的資料如國家代碼或郵遞區號。VARCHAR型別用於儲存可變長度的字串,是最常用的字串型別,適合儲存長度變化較大的資料如姓名或地址。TEXT系列型別包括TINYTEXT、TEXT、MEDIUMTEXT與LONGTEXT,用於儲存大量文字資料如文章內容或產品描述。ENUM型別用於儲存預定義的值集合,適合狀態欄位等有限選項的情況。在選擇字串型別時,需要考慮字元集與排序規則的設定,UTF8MB4是目前推薦的字元集,它完整支援Unicode包括表情符號。

-- 字串型別使用範例
-- 展示各種字串型別的定義與最佳實務

-- 建立使用者資料表
-- 展示字串型別的正確使用
CREATE TABLE users (
    -- 使用者ID
    user_id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,

    -- 使用者名稱使用VARCHAR
    -- 指定合理的最大長度
    username VARCHAR(50) NOT NULL,

    -- 電子郵件使用VARCHAR
    -- 電子郵件地址標準最長254字元
    email VARCHAR(255) NOT NULL,

    -- 密碼雜湊使用CHAR
    -- bcrypt產生的雜湊值固定60字元
    password_hash CHAR(60) NOT NULL,

    -- 手機號碼使用VARCHAR
    -- 國際格式最長約20字元
    phone VARCHAR(20),

    -- 國家代碼使用CHAR
    -- ISO 3166-1 alpha-2固定2字元
    country_code CHAR(2) DEFAULT 'TW',

    -- 郵遞區號使用VARCHAR
    -- 各國格式不同,預留空間
    postal_code VARCHAR(20),

    -- 個人簡介使用TEXT
    -- 允許較長的自我介紹
    bio TEXT,

    -- 使用者狀態使用ENUM
    -- 預定義的有限選項
    status ENUM('active', 'inactive', 'suspended', 'deleted')
        DEFAULT 'active',

    -- 興趣標籤使用SET
    -- 允許多選的預定義選項
    interests SET('technology', 'sports', 'music', 'art', 'travel'),

    -- 唯一約束
    UNIQUE KEY uk_username (username),
    UNIQUE KEY uk_email (email),

    -- 索引
    INDEX idx_status (status),
    INDEX idx_country (country_code)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- 插入測試資料
INSERT INTO users (username, email, password_hash, country_code, status, interests)
VALUES
    ('john_doe', '[email protected]', '$2b$10$...', 'TW', 'active', 'technology,music'),
    ('jane_smith', '[email protected]', '$2b$10$...', 'US', 'active', 'art,travel');

-- 查詢特定興趣的使用者
-- SET型別使用FIND_IN_SET函式
SELECT username, email
FROM users
WHERE FIND_IN_SET('technology', interests) > 0;

日期時間型別是處理時間資料的專用型別。DATE型別儲存日期,TIME型別儲存時間,DATETIME型別同時儲存日期與時間。TIMESTAMP型別也儲存日期時間,但有一些特殊行為:它會自動轉換時區,且範圍較小(1970年至2038年)。YEAR型別只儲存年份。在選擇日期時間型別時,需要考慮應用的時區處理需求。如果應用需要處理多時區,TIMESTAMP的自動時區轉換特性可能很有用;如果需要儲存精確的本地時間,則DATETIME更合適。對於需要自動記錄資料建立或更新時間的欄位,可以使用DEFAULT CURRENT_TIMESTAMP與ON UPDATE CURRENT_TIMESTAMP子句。

-- 日期時間型別使用範例
-- 展示時間相關欄位的設計與操作

-- 建立訂單資料表
-- 展示日期時間型別的應用
CREATE TABLE orders (
    -- 訂單ID
    order_id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,

    -- 使用者ID
    user_id INT UNSIGNED NOT NULL,

    -- 訂單日期使用DATE
    -- 只需要日期,不需要時間
    order_date DATE NOT NULL,

    -- 預計送達日期
    estimated_delivery DATE,

    -- 配送時段使用TIME
    -- 儲存如14:00:00這樣的時間
    delivery_time_start TIME,
    delivery_time_end TIME,

    -- 建立時間使用TIMESTAMP
    -- 自動記錄,支援時區轉換
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,

    -- 更新時間
    -- 自動更新為當前時間
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,

    -- 實際送達時間使用DATETIME
    -- 儲存完整的日期時間
    actual_delivery_at DATETIME,

    -- 訂單年份使用YEAR
    -- 用於年度統計快速查詢
    order_year YEAR,

    -- 訂單狀態
    status ENUM('pending', 'processing', 'shipped', 'delivered', 'cancelled')
        DEFAULT 'pending',

    -- 訂單金額
    total_amount DECIMAL(12, 2) NOT NULL,

    -- 索引
    INDEX idx_user (user_id),
    INDEX idx_order_date (order_date),
    INDEX idx_status (status),
    INDEX idx_year (order_year),

    -- 外鍵
    FOREIGN KEY (user_id) REFERENCES users(user_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- 插入訂單資料
INSERT INTO orders (user_id, order_date, estimated_delivery,
                    delivery_time_start, delivery_time_end,
                    order_year, total_amount)
VALUES
    (1, '2025-11-25', '2025-11-28', '14:00:00', '18:00:00', 2025, 1299.00),
    (2, '2025-11-25', '2025-11-27', '09:00:00', '12:00:00', 2025, 599.00);

-- 查詢本月訂單統計
SELECT
    DATE_FORMAT(order_date, '%Y-%m') AS 月份,
    COUNT(*) AS 訂單數,
    SUM(total_amount) AS 總金額
FROM orders
WHERE order_date >= DATE_FORMAT(CURRENT_DATE, '%Y-%m-01')
GROUP BY DATE_FORMAT(order_date, '%Y-%m');

-- 計算訂單處理時間
SELECT
    order_id,
    TIMESTAMPDIFF(HOUR, created_at, actual_delivery_at) AS 處理時數
FROM orders
WHERE actual_delivery_at IS NOT NULL;

二進位型別用於儲存二進位資料,如圖片、文件或加密資料。BINARY與VARBINARY型別分別用於固定長度與可變長度的二進位字串,類似於CHAR與VARCHAR。BLOB系列型別包括TINYBLOB、BLOB、MEDIUMBLOB與LONGBLOB,用於儲存大型二進位物件。雖然MySQL支援將檔案直接儲存在BLOB欄位中,但在現代應用架構中,通常建議將大型檔案儲存在檔案系統或物件儲存服務中,而資料庫只儲存檔案的路徑或識別碼。這種做法可以減輕資料庫的負擔,提升備份與還原的效率,並更好地利用CDN等內容分發機制。

JSON型別是MySQL 5.7引入的原生JSON支援,它允許我們直接儲存與操作JSON文件。與將JSON儲存為文字相比,JSON型別提供了自動驗證、最佳化的儲存格式,以及豐富的JSON函式支援。我們可以使用JSON_EXTRACT函式提取JSON中的值,使用JSON_SET函式修改JSON中的值,還可以在JSON欄位上建立虛擬欄位與索引以提升查詢效能。JSON型別非常適合儲存結構靈活或半結構化的資料,如使用者偏好設定、產品規格等。

-- JSON型別使用範例
-- 展示JSON資料的儲存與查詢

-- 建立商品詳情資料表
-- 使用JSON儲存靈活的屬性
CREATE TABLE product_details (
    -- 商品ID
    product_id INT UNSIGNED PRIMARY KEY,

    -- 商品名稱
    product_name VARCHAR(200) NOT NULL,

    -- 商品規格使用JSON
    -- 不同類別商品有不同的規格屬性
    specifications JSON,

    -- 商品標籤使用JSON陣列
    tags JSON,

    -- 價格歷史使用JSON陣列
    price_history JSON,

    -- 從JSON中提取的虛擬欄位
    -- 用於建立索引提升查詢效能
    brand VARCHAR(100) AS (JSON_UNQUOTE(JSON_EXTRACT(specifications, '$.brand'))) STORED,
    color VARCHAR(50) AS (JSON_UNQUOTE(JSON_EXTRACT(specifications, '$.color'))) STORED,

    -- 索引
    INDEX idx_brand (brand),
    INDEX idx_color (color)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- 插入JSON資料
INSERT INTO product_details (product_id, product_name, specifications, tags, price_history)
VALUES (
    1,
    'iPhone 15 Pro',
    JSON_OBJECT(
        'brand', 'Apple',
        'color', 'Natural Titanium',
        'storage', '256GB',
        'screen_size', '6.1 inch',
        'processor', 'A17 Pro',
        'camera', JSON_OBJECT(
            'main', '48MP',
            'ultra_wide', '12MP',
            'telephoto', '12MP'
        )
    ),
    JSON_ARRAY('smartphone', '5G', 'titanium', 'pro'),
    JSON_ARRAY(
        JSON_OBJECT('date', '2025-01-01', 'price', 36900),
        JSON_OBJECT('date', '2025-06-01', 'price', 34900),
        JSON_OBJECT('date', '2025-11-01', 'price', 32900)
    )
);

-- 查詢JSON資料
-- 使用->運算子提取值(等同於JSON_EXTRACT)
SELECT
    product_name,
    specifications->>'$.brand' AS 品牌,
    specifications->>'$.storage' AS 儲存容量,
    specifications->'$.camera.main' AS 主相機
FROM product_details
WHERE product_id = 1;

-- 使用JSON_CONTAINS查詢
-- 檢查陣列中是否包含特定值
SELECT product_name
FROM product_details
WHERE JSON_CONTAINS(tags, '"5G"');

-- 使用JSON_TABLE展開JSON陣列
-- 將價格歷史展開為表格格式
SELECT
    p.product_name,
    j.price_date,
    j.price
FROM product_details p,
JSON_TABLE(
    p.price_history,
    '$[*]' COLUMNS(
        price_date DATE PATH '$.date',
        price DECIMAL(10,2) PATH '$.price'
    )
) AS j
WHERE p.product_id = 1;

-- 更新JSON中的特定欄位
UPDATE product_details
SET specifications = JSON_SET(
    specifications,
    '$.price', 32900,
    '$.in_stock', true
)
WHERE product_id = 1;

空間資料型別用於儲存地理位置資料,MySQL支援OpenGIS標準中定義的各種幾何型別。POINT型別儲存單一座標點,LINESTRING型別儲存線段,POLYGON型別儲存多邊形區域。這些型別配合空間函式可以執行複雜的地理查詢,如計算兩點間的距離、判斷點是否在區域內,或尋找某範圍內的所有位置。空間資料型別在地圖應用、物流系統、位置服務等場景中非常有用。要有效使用空間資料型別,通常需要建立空間索引以提升查詢效能。

表格連線是SQL中最重要的操作之一,它允許我們將相關的表格組合在一起查詢。MySQL支援多種連線型別:INNER JOIN返回兩個表格中匹配的記錄,LEFT JOIN返回左表的所有記錄與右表中匹配的記錄,RIGHT JOIN則相反,CROSS JOIN產生兩個表格的笛卡爾積。理解每種連線的語義與效能特性,對於撰寫正確且高效的查詢至關重要。在設計查詢時,應當確保連線欄位上有適當的索引,並注意連線的順序與條件的撰寫方式。

-- 表格連線使用範例
-- 展示各種JOIN操作與效能優化

-- 建立示範資料表
-- 部門表
CREATE TABLE departments (
    dept_id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    dept_name VARCHAR(100) NOT NULL,
    location VARCHAR(100),
    INDEX idx_name (dept_name)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- 員工表
CREATE TABLE employees (
    emp_id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    emp_name VARCHAR(100) NOT NULL,
    dept_id INT UNSIGNED,
    manager_id INT UNSIGNED,
    hire_date DATE NOT NULL,
    salary DECIMAL(10, 2) NOT NULL,
    INDEX idx_dept (dept_id),
    INDEX idx_manager (manager_id),
    INDEX idx_hire_date (hire_date),
    FOREIGN KEY (dept_id) REFERENCES departments(dept_id),
    FOREIGN KEY (manager_id) REFERENCES employees(emp_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- 專案表
CREATE TABLE projects (
    project_id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    project_name VARCHAR(200) NOT NULL,
    start_date DATE,
    end_date DATE,
    budget DECIMAL(12, 2)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- 員工專案關聯表
CREATE TABLE employee_projects (
    emp_id INT UNSIGNED,
    project_id INT UNSIGNED,
    role VARCHAR(50),
    hours_worked INT UNSIGNED DEFAULT 0,
    PRIMARY KEY (emp_id, project_id),
    FOREIGN KEY (emp_id) REFERENCES employees(emp_id),
    FOREIGN KEY (project_id) REFERENCES projects(project_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- INNER JOIN範例
-- 查詢員工與其所屬部門
-- 只返回有部門的員工
SELECT
    e.emp_id,
    e.emp_name,
    d.dept_name,
    d.location
FROM employees e
INNER JOIN departments d ON e.dept_id = d.dept_id
ORDER BY d.dept_name, e.emp_name;

-- LEFT JOIN範例
-- 查詢所有員工,包含沒有部門的
SELECT
    e.emp_id,
    e.emp_name,
    COALESCE(d.dept_name, '未分配') AS dept_name
FROM employees e
LEFT JOIN departments d ON e.dept_id = d.dept_id
ORDER BY e.emp_name;

-- RIGHT JOIN範例
-- 查詢所有部門,包含沒有員工的
SELECT
    d.dept_name,
    COUNT(e.emp_id) AS 員工數
FROM employees e
RIGHT JOIN departments d ON e.dept_id = d.dept_id
GROUP BY d.dept_id, d.dept_name
ORDER BY 員工數 DESC;

-- 自我連線(Self Join)範例
-- 查詢員工與其主管
SELECT
    e.emp_name AS 員工姓名,
    m.emp_name AS 主管姓名
FROM employees e
LEFT JOIN employees m ON e.manager_id = m.emp_id
ORDER BY m.emp_name, e.emp_name;

-- 多表連線範例
-- 查詢員工參與的專案詳情
SELECT
    e.emp_name,
    d.dept_name,
    p.project_name,
    ep.role,
    ep.hours_worked
FROM employees e
INNER JOIN departments d ON e.dept_id = d.dept_id
INNER JOIN employee_projects ep ON e.emp_id = ep.emp_id
INNER JOIN projects p ON ep.project_id = p.project_id
WHERE p.end_date IS NULL OR p.end_date >= CURRENT_DATE
ORDER BY e.emp_name, p.project_name;

-- 使用子查詢與連線
-- 查詢高於部門平均薪資的員工
SELECT
    e.emp_name,
    e.salary,
    d.dept_name,
    dept_avg.avg_salary AS 部門平均
FROM employees e
INNER JOIN departments d ON e.dept_id = d.dept_id
INNER JOIN (
    SELECT dept_id, AVG(salary) AS avg_salary
    FROM employees
    GROUP BY dept_id
) dept_avg ON e.dept_id = dept_avg.dept_id
WHERE e.salary > dept_avg.avg_salary
ORDER BY d.dept_name, e.salary DESC;

-- 使用EXPLAIN分析查詢效能
EXPLAIN SELECT
    e.emp_name,
    d.dept_name
FROM employees e
INNER JOIN departments d ON e.dept_id = d.dept_id
WHERE d.dept_name = 'Engineering';

查詢效能優化是資料庫開發中的重要議題。對於涉及連線的查詢,索引的設計尤為關鍵。連線欄位通常應該建立索引,這可以顯著加速表格的匹配過程。此外,WHERE子句中的過濾條件也應該有對應的索引。使用EXPLAIN命令可以分析查詢的執行計劃,找出潛在的效能瓶頸。在複雜查詢中,連線的順序、子查詢的改寫、以及適當的資料正規化程度都會影響效能。理解這些因素並運用最佳實務,可以大幅提升資料庫應用的回應速度。

-- 查詢優化範例
-- 展示索引策略與查詢改寫

-- 建立複合索引
-- 適用於多欄位的查詢條件
CREATE INDEX idx_emp_dept_hire
ON employees(dept_id, hire_date);

-- 建立覆蓋索引
-- 包含查詢所需的所有欄位,避免回表
CREATE INDEX idx_emp_cover
ON employees(dept_id, emp_name, salary);

-- 優化前的查詢
-- 可能導致全表掃描
SELECT emp_name, salary
FROM employees
WHERE dept_id IN (
    SELECT dept_id FROM departments WHERE location = 'Taipei'
);

-- 優化後的查詢
-- 使用JOIN替代子查詢
SELECT e.emp_name, e.salary
FROM employees e
INNER JOIN departments d ON e.dept_id = d.dept_id
WHERE d.location = 'Taipei';

-- 使用EXISTS替代IN
-- 在某些情況下效能更好
SELECT e.emp_name, e.salary
FROM employees e
WHERE EXISTS (
    SELECT 1 FROM departments d
    WHERE d.dept_id = e.dept_id
    AND d.location = 'Taipei'
);

-- 分頁查詢優化
-- 傳統OFFSET在大量資料時效能差
SELECT emp_id, emp_name
FROM employees
ORDER BY emp_id
LIMIT 10 OFFSET 10000;

-- 使用鍵集分頁(Keyset Pagination)
-- 效能更好的替代方案
SELECT emp_id, emp_name
FROM employees
WHERE emp_id > 10000
ORDER BY emp_id
LIMIT 10;

-- 統計查詢優化
-- 避免在大表上使用COUNT(*)
-- 使用估計值或快取
SELECT TABLE_ROWS
FROM information_schema.TABLES
WHERE TABLE_NAME = 'employees';

-- 建立統計摘要表
CREATE TABLE daily_stats (
    stat_date DATE PRIMARY KEY,
    total_employees INT UNSIGNED,
    total_salary DECIMAL(15, 2),
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB;

-- 定期更新統計
INSERT INTO daily_stats (stat_date, total_employees, total_salary)
SELECT CURRENT_DATE, COUNT(*), SUM(salary)
FROM employees
ON DUPLICATE KEY UPDATE
    total_employees = VALUES(total_employees),
    total_salary = VALUES(total_salary);

總結而言,MySQL的資料型別系統提供了豐富的選項來滿足各種資料儲存需求。正確選擇資料型別需要考慮資料的性質、取值範圍、精度要求、儲存效率與查詢效能等多個因素。表格連線是關聯式資料庫的核心機制,熟練掌握各種連線型別與優化技巧,對於開發高效能的資料庫應用至關重要。在實際開發中,應當結合具體的業務需求與效能目標,運用本文介紹的知識與技巧,設計出既符合功能需求又具備良好效能的資料庫結構與查詢語句。