1. Yêu cầu hệ thống

Thành phầnYêu cầu tối thiểuKhuyến nghị
SQL Server2019 (15.x)2022 (16.x)
CollationVietnamese_CI_ASVietnamese_CI_AS
RAM8 GB16 GB+
Disk50 GB SSD200 GB+ NVMe SSD
CPU4 cores8 cores+

Tương thích Cloud

Nền tảngPhiên bảnGhi chú
Azure SQL DatabaseGeneral Purpose, S3+Fully managed, auto-backup
Azure SQL Managed InstanceGeneral PurposeGần giống on-premise nhất
Amazon RDS for SQL ServerStandard EditionCần bật Vietnamese collation khi tạo
Google Cloud SQL for SQL Server2019/2022Hỗ trợ Vietnamese collation

2. Các bước triển khai

Bước 1: Tạo Database

-- Tạo database với collation Tiếng Việt
IF NOT EXISTS (SELECT name FROM sys.databases WHERE name = N'HucaDB')
BEGIN
    CREATE DATABASE HucaDB
    COLLATE Vietnamese_CI_AS;
END
GO

USE HucaDB;
GO
:::caution Lưu ý Collation Phải thiết lập Vietnamese_CI_AS ngay khi tạo database. Việc đổi collation sau sẽ rất phức tạp và đòi hỏi rebuild toàn bộ indexes. :::

Bước 2: Chạy file SQL

Thực thi file huca-database-design.sql theo đúng thứ tự (file đã được sắp xếp sẵn):
# Dùng sqlcmd
sqlcmd -S <server> -d HucaDB -U <user> -P <password> -i huca-database-design.sql

# Hoặc dùng SQL Server Management Studio (SSMS):
# File → Open → huca-database-design.sql → Execute (F5)

Bước 3: Xác nhận

-- Kiểm tra số lượng bảng đã tạo (kết quả mong đợi: 45)
SELECT COUNT(*) AS TableCount
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE = 'BASE TABLE'
  AND TABLE_NAME LIKE 't_huca_%';

-- Xem danh sách tất cả bảng
SELECT TABLE_NAME
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE = 'BASE TABLE'
  AND TABLE_NAME LIKE 't_huca_%'
ORDER BY TABLE_NAME;

3. Thứ tự tạo bảng (phụ thuộc FK)

Bảng trong file SQL đã được sắp xếp đúng thứ tự phụ thuộc:
1. Danh mục (không có FK)
   provinces → faculties → academic_years → classes
   roles → permissions → role_permissions

2. Giai đoạn 1 (FK đến danh mục)
   users → user_roles → account_links
   liaison_committees → committee_terms → committee_members
   groups → group_members
   posts → comments → reactions → media
   article_categories → articles
   events → event_registrations
   fundraising_campaigns → donations → payments
   conversations → conversation_members → messages
   notifications → email_templates → email_logs

3. Giai đoạn 2 (FK đến users, events)
   event_attendances → user_locations → device_tokens

4. Giai đoạn 3 (FK đến users, events)
   training_programs → program_registrations → certificates
   mentors → mentorship_matches → mentorship_appointments
   exam_banks → exams → exam_questions → exam_submissions
   points → badges → user_badges → leaderboards

5. Giai đoạn 4 (FK đến users + ALTER TABLE exams)
   companies → company_members
   [ALTER TABLE exams ADD FK_exams_Company]
   jobs → job_applications
   vouchers → voucher_claims
   b2b_opportunities → b2b_responses

6. Hỗ trợ
   audit_logs → statistics → admin_requests

4. Triển khai theo giai đoạn

Có thể triển khai từng phần theo tiến độ dự án:

Chỉ Giai đoạn 1 (Web)

-- Chạy đến hết PHẦN 1 trong file SQL
-- Dừng trước dòng: -- PHẦN 2: GIAI ĐOẠN 2 - APP DI ĐỘNG

Bổ sung Giai đoạn 2 (Mobile) — sau 3 tháng

-- Chạy tiếp PHẦN 2 từ file SQL
-- t_huca_event_attendances
-- t_huca_user_locations
-- t_huca_device_tokens

Bổ sung Giai đoạn 3 & 4 — sau 6 và 9 tháng

Tương tự, chạy PHẦN 3 rồi PHẦN 4 theo tiến độ.

5. Migration (Cập nhật schema)

Khi cần thay đổi schema sau khi đã có dữ liệu, sử dụng migration scripts thay vì chạy lại toàn bộ file.

Quy ước đặt tên migration file

migrations/
├── V001__initial_schema.sql          ← File gốc
├── V002__add_users_bio_field.sql     ← Thêm cột mới
├── V003__add_index_jobs_deadline.sql ← Thêm index
└── V004__phase3_gamification.sql     ← Tính năng mới

Ví dụ migration thêm cột

-- V002__add_users_bio_field.sql
-- Thêm trường Bio vào t_huca_users

IF NOT EXISTS (
    SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS
    WHERE TABLE_NAME = 't_huca_users'
      AND COLUMN_NAME = 'Bio'
)
BEGIN
    ALTER TABLE t_huca_users
        ADD Bio NVARCHAR(1000);

    PRINT 'Added Bio column to t_huca_users';
END
ELSE
BEGIN
    PRINT 'Bio column already exists, skipping.';
END
GO

Ví dụ migration thêm index

-- V003__add_index_jobs_deadline.sql
IF NOT EXISTS (
    SELECT 1 FROM sys.indexes
    WHERE name = 'IX_jobs_Deadline'
      AND object_id = OBJECT_ID('t_huca_jobs')
)
BEGIN
    CREATE INDEX IX_jobs_Deadline ON t_huca_jobs(Deadline)
        WHERE Deadline IS NOT NULL AND Status = 'Active';
    PRINT 'Created IX_jobs_Deadline';
END
GO

6. Backup & Recovery

Lịch backup khuyến nghị

Loại backupTần suấtRetention
Full backupHàng ngày (03:00 AM)30 ngày
DifferentialMỗi 6 giờ7 ngày
Transaction logMỗi 15 phút3 ngày

Lệnh backup cơ bản

-- Full backup
BACKUP DATABASE HucaDB
TO DISK = 'D:\Backups\HucaDB_Full_20260101.bak'
WITH COMPRESSION, STATS = 10;

-- Restore
RESTORE DATABASE HucaDB
FROM DISK = 'D:\Backups\HucaDB_Full_20260101.bak'
WITH REPLACE, RECOVERY;

7. Dữ liệu khởi tạo (Seed Data)

File SQL bao gồm sẵn seed data cho các bảng danh mục:
-- Sau khi chạy file SQL, kiểm tra seed data:
SELECT * FROM t_huca_roles;           -- 6 vai trò
SELECT * FROM t_huca_article_categories; -- 5 danh mục tin
SELECT * FROM t_huca_badges;          -- 8 huy hiệu
SELECT * FROM t_huca_email_templates; -- 5 mẫu email
SELECT COUNT(*) FROM t_huca_permissions; -- 23 quyền hạn

Thêm dữ liệu Tỉnh/Thành phố

-- Chạy riêng script seed provinces (63 tỉnh/thành)
-- Ví dụ:
INSERT INTO t_huca_provinces (Name, Code, Region, Latitude, Longitude) VALUES
(N'Hà Nội',         'HN',  N'Miền Bắc',  21.0285, 105.8542),
(N'TP. Hồ Chí Minh','HCM', N'Miền Nam',  10.8231, 106.6297),
(N'Đà Nẵng',        'DN',  N'Miền Trung', 16.0544, 108.2022),
(N'Hải Phòng',      'HP',  N'Miền Bắc',  20.8449, 106.6881),
-- ... (63 tỉnh/thành đầy đủ)

Thêm dữ liệu Khoa/Viện HUCE

INSERT INTO t_huca_faculties (Name, ShortName, Code) VALUES
(N'Khoa Xây dựng Dân dụng và Công nghiệp', N'Khoa XD', 'XD'),
(N'Khoa Công trình Thủy', N'Khoa CTT', 'CTT'),
(N'Khoa Kỹ thuật Hạ tầng Đô thị', N'Khoa KTHĐT', 'KTHDT'),
(N'Khoa Cầu đường', N'Khoa CD', 'CD'),
(N'Khoa Kiến trúc Quy hoạch', N'Khoa KTQH', 'KTQH'),
(N'Khoa Kinh tế và Quản lý Xây dựng', N'Khoa KTQL', 'KTQL'),
(N'Khoa Vật liệu Xây dựng', N'Khoa VLXD', 'VLXD'),
(N'Khoa Cơ học Kỹ thuật và Tự động hóa', N'Khoa CHKT', 'CHKT'),
(N'Khoa Công nghệ Thông tin', N'Khoa CNTT', 'CNTT'),
(N'Khoa Lý luận Chính trị', N'Khoa LLCT', 'LLCT');

8. Performance Tuning

Index Statistics cập nhật

-- Cập nhật statistics sau khi import dữ liệu lớn
UPDATE STATISTICS t_huca_users WITH FULLSCAN;
UPDATE STATISTICS t_huca_events WITH FULLSCAN;
UPDATE STATISTICS t_huca_posts WITH FULLSCAN;

-- Hoặc cập nhật toàn bộ database
EXEC sp_updatestats;

Rebuild Index định kỳ

-- Rebuild tất cả index bị phân mảnh > 30%
-- Nên chạy trong maintenance window (cuối tuần)
DECLARE @TableName NVARCHAR(255);
DECLARE @SQL NVARCHAR(MAX);

DECLARE cur CURSOR FOR
    SELECT DISTINCT OBJECT_NAME(i.object_id)
    FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, 'LIMITED') ips
    JOIN sys.indexes i ON i.object_id = ips.object_id AND i.index_id = ips.index_id
    WHERE ips.avg_fragmentation_in_percent > 30
      AND OBJECT_NAME(i.object_id) LIKE 't_huca_%';

OPEN cur;
FETCH NEXT FROM cur INTO @TableName;
WHILE @@FETCH_STATUS = 0
BEGIN
    SET @SQL = 'ALTER INDEX ALL ON ' + @TableName + ' REBUILD';
    EXEC sp_executesql @SQL;
    FETCH NEXT FROM cur INTO @TableName;
END
CLOSE cur;
DEALLOCATE cur;

Bổ sung Spatial Index (Giai đoạn 2)

Khi tính năng “Tìm CSV lân cận” đi vào hoạt động với lượng dữ liệu lớn:
-- Thêm cột geography để tìm kiếm theo bán kính nhanh hơn
ALTER TABLE t_huca_user_locations
    ADD LocationGeo AS geography::Point(Latitude, Longitude, 4326) PERSISTED;

CREATE SPATIAL INDEX SIX_user_locations_Geo
ON t_huca_user_locations(LocationGeo)
USING GEOGRAPHY_GRID
WITH (CELLS_PER_OBJECT = 16);

Full-Text Index (Tìm kiếm nâng cao)

-- Tạo Full-Text Catalog
CREATE FULLTEXT CATALOG HucaFTCatalog AS DEFAULT;

-- Full-Text Index trên bảng users (tìm kiếm theo tên, công ty)
CREATE FULLTEXT INDEX ON t_huca_users(FullName, Company, JobTitle)
    KEY INDEX PK__t_huca_u__3214EC071234
    ON HucaFTCatalog;

-- Full-Text Index trên bảng articles
CREATE FULLTEXT INDEX ON t_huca_articles(Title, Content)
    KEY INDEX PK__t_huca_a__5678
    ON HucaFTCatalog;

-- Truy vấn Full-Text Search
SELECT Id, FullName, Company
FROM t_huca_users
WHERE CONTAINS((FullName, Company), N'"kỹ sư" AND "xây dựng"');

9. Monitoring

Kiểm tra kích thước database

SELECT
    name AS DatabaseName,
    size * 8 / 1024 AS SizeMB,
    max_size
FROM sys.master_files
WHERE database_id = DB_ID('HucaDB');

Kiểm tra bảng lớn nhất

SELECT TOP 10
    t.NAME AS TableName,
    p.rows AS RowCount,
    SUM(a.total_pages) * 8 / 1024 AS TotalSpaceMB
FROM sys.tables t
JOIN sys.indexes i ON t.OBJECT_ID = i.object_id
JOIN sys.partitions p ON i.object_id = p.OBJECT_ID AND i.index_id = p.index_id
JOIN sys.allocation_units a ON p.partition_id = a.container_id
WHERE t.NAME LIKE 't_huca_%'
GROUP BY t.Name, p.Rows
ORDER BY TotalSpaceMB DESC;

Kiểm tra slow queries

SELECT TOP 20
    qs.total_elapsed_time / qs.execution_count / 1000 AS AvgElapsedMs,
    qs.execution_count,
    SUBSTRING(st.text, (qs.statement_start_offset/2)+1,
        ((CASE qs.statement_end_offset WHEN -1 THEN DATALENGTH(st.text)
          ELSE qs.statement_end_offset END - qs.statement_start_offset)/2)+1
    ) AS QueryText
FROM sys.dm_exec_query_stats qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) st
WHERE st.text LIKE '%t_huca_%'
ORDER BY AvgElapsedMs DESC;