一、基礎概念
1. 什么是數據庫?DBMS的作用是什么?
-
數據庫:是按照數據結構來組織、存儲和管理數據的倉庫。它允許用戶高效地訪問和管理數據。
-
DBMS(數據庫管理系統):是一種軟件系統,用于創建和管理數據庫。它的作用包括:
-
數據定義(DDL)
-
數據操作(DML)
-
數據查詢(DQL)
-
數據控制(安全性、完整性、并發性等)
-
2. SQL的全稱是什么?它有哪些分類?
-
SQL全稱:Structured Query Language(結構化查詢語言)。
-
分類:
-
DDL(Data Definition Language):用于定義或修改數據庫對象(如表、索引等),例如
CREATE
、ALTER
、DROP
。 -
DML(Data Manipulation Language):用于操作數據庫中的數據,例如
INSERT
、UPDATE
、DELETE
。 -
DQL(Data Query Language):用于查詢數據庫中的數據,例如
SELECT
。 -
DCL(Data Control Language):用于控制權限和訪問,例如
GRANT
、REVOKE
。
-
3. MySQL的默認端口號是多少?如何修改?
-
默認端口號:3306。
-
修改方法:
-
編輯MySQL配置文件
my.cnf
或my.ini
。 -
找到
[mysqld]
部分,修改或添加port=新端口號
。 -
重啟MySQL服務以使更改生效。
-
4. MySQL中CHAR和VARCHAR的區別?
特性 | CHAR | VARCHAR |
---|---|---|
存儲空間 | 固定長度 | 可變長度 |
性能 | 較快(固定長度便于計算) | 較慢(需要額外存儲長度信息) |
使用場景 | 短且固定長度的數據 | 長度不確定的數據 |
5. DATETIME和TIMESTAMP類型的區別?
特性 | DATETIME | TIMESTAMP |
---|---|---|
存儲范圍 | 1000-01-01 00:00:00 到 9999-12-31 23:59:59 | 1970-01-01 00:00:01 到 2038-01-19 03:14:07 |
存儲大小 | 8字節 | 4字節 |
是否受時區影響 | 不受影響 | 受影響 |
6. 如何創建一個包含自增主鍵的表?
CREATE TABLE example_table (id INT AUTO_INCREMENT PRIMARY KEY,name VARCHAR(50) NOT NULL );
7. TRUNCATE TABLE和DELETE的區別?
特性 | TRUNCATE TABLE | DELETE |
---|---|---|
操作方式 | 清空整個表并重置自增計數器 | 刪除指定條件的記錄 |
事務支持 | 不支持事務回滾 | 支持事務回滾 |
觸發器觸發 | 不會觸發觸發器 | 會觸發觸發器 |
執行速度 | 快 | 慢 |
8. 什么是主鍵(Primary Key)?什么是外鍵(Foreign Key)?
-
主鍵(Primary Key):唯一標識表中每一行數據的字段或字段組合,不允許為空且值必須唯一。
-
外鍵(Foreign Key):用于建立和加強兩個表之間的關系,確保引用完整性。外鍵通常指向另一個表的主鍵。
9. 如何查看當前數據庫中的所有表?
SHOW TABLES;
10. WHERE和HAVING的區別?
特性 | WHERE | HAVING |
---|---|---|
使用場景 | 過濾行數據(在聚合前) | 過濾聚合后的結果 |
適用對象 | 單個列 | 聚合函數或分組列 |
查詢階段 | 在GROUP BY之前執行 | 在GROUP BY之后執行 |
二、SQL語法與操作
1. 寫出查詢表中前10條記錄的SQL語句。
SELECT * FROM table_name LIMIT 10;
2. 如何對查詢結果去重(DISTINCT的用法)?
-
使用
DISTINCT
關鍵字去除重復值,僅保留唯一值。
SELECT DISTINCT column_name FROM table_name;
示例:查詢所有唯一的部門名稱。
SELECT DISTINCT department FROM employees;
3. INNER JOIN和LEFT JOIN的區別?
特性 | INNER JOIN | LEFT JOIN |
---|---|---|
返回數據 | 只返回兩個表中匹配的記錄 | 返回左表的所有記錄,右表無匹配則為NULL |
數據完整性 | 不包含不匹配的記錄 | 包含左表的所有記錄 |
示例:
-- INNER JOIN 示例 SELECT a.id, a.name, b.department FROM employees a INNER JOIN departments b ON a.department_id = b.id; ? -- LEFT JOIN 示例 SELECT a.id, a.name, b.department FROM employees a LEFT JOIN departments b ON a.department_id = b.id;
4. 如何實現分頁查詢?(LIMIT和OFFSET)
-
使用
LIMIT
和OFFSET
實現分頁查詢。
SELECT * FROM table_name LIMIT 每頁記錄數 OFFSET 起始偏移量;
示例:查詢第2頁的數據,每頁10條記錄。
SELECT * FROM table_name LIMIT 10 OFFSET 10;
5. 如何將兩個查詢結果合并(UNION和UNION ALL)?
-
UNION:合并兩個查詢結果并去重。
-
UNION ALL:合并兩個查詢結果,不去重。
示例:
-- UNION 示例 SELECT name FROM table1 UNION SELECT name FROM table2;-- UNION ALL 示例 SELECT name FROM table1 UNION ALL SELECT name FROM table2;
6. 如何創建索引?舉例說明。
-
使用
CREATE INDEX
創建索引。
CREATE INDEX index_name ON table_name (column_name);
示例:為 employees
表的 name
列創建索引。
CREATE INDEX idx_employee_name ON employees (name);
7. 如何修改表結構(添加/刪除列)?
-
添加列:
ALTER TABLE table_name ADD COLUMN column_name 數據類型;
示例:為 employees
表添加 age
列。
ALTER TABLE employees ADD COLUMN age INT;
-
刪除列:
ALTER TABLE table_name DROP COLUMN column_name;
示例:刪除 employees
表的 age
列。
ALTER TABLE employees DROP COLUMN age;
8. 什么是子查詢?舉例說明。
-
子查詢:嵌套在另一個查詢中的查詢,通常用于提供條件或過濾數據。
SELECT column_name FROM table_name WHERE column_name IN (子查詢);
示例:查詢工資高于平均工資的員工。
SELECT name, salary FROM employees WHERE salary > (SELECT AVG(salary) FROM employees);
9. 如何批量插入數據?
-
使用
INSERT INTO
插入多行數據。
INSERT INTO table_name (column1, column2) VALUES (value1, value2), (value3, value4), ...;
示例:向 employees
表批量插入兩條記錄。
INSERT INTO employees (name, department_id) VALUES ('Alice', 1), ('Bob', 2);
10. BETWEEN和IN的用法區別?
-
BETWEEN:用于指定一個范圍(包括邊界值)。
SELECT * FROM table_name WHERE column_name BETWEEN value1 AND value2;
示例:查詢年齡在20到30之間的員工。
SELECT * FROM employees WHERE age BETWEEN 20 AND 30;
-
IN:用于指定多個離散值。
SELECT * FROM table_name WHERE column_name IN (value1, value2, value3);
示例:查詢部門ID為1、2或3的員工。
SELECT * FROM employees WHERE department_id IN (1, 2, 3);
三、索引與性能優化
1. 什么是索引?為什么需要索引?
-
索引:是一種特殊的數據結構(如B-Tree),用于快速定位數據,類似于書的目錄。
-
為什么需要索引:
-
提高查詢效率,減少掃描全表的時間。
-
加速排序和分組操作。
-
支持唯一性約束。
-
2. 索引的類型有哪些?(B-Tree、哈希、全文索引)
類型 | 描述 |
---|---|
B-Tree索引 | 最常用的索引類型,支持范圍查詢和排序,適合大多數場景。 |
哈希索引 | 使用哈希函數存儲鍵值對,查詢速度非常快,但不支持范圍查詢或部分匹配查詢。 |
全文索引 | 專門用于全文搜索,支持復雜的文本匹配(如MySQL中的 FULLTEXT )。 |
3. 索引的優缺點是什么?
優點 | 缺點 |
---|---|
提高查詢效率 | 增加插入、更新和刪除操作的開銷 |
減少磁盤I/O | 占用額外的存儲空間 |
支持排序和分組 | 在某些情況下可能導致查詢計劃變差 |
4. 什么情況下索引會失效?
-
索引失效的情況:
-
使用了函數或表達式操作索引列,例如
WHERE YEAR(date_column) = 2023
。 -
數據類型不匹配,例如字符串與數字比較。
-
使用了模糊查詢前綴通配符,例如
WHERE column LIKE '%value'
。 -
查詢條件中使用了
OR
且部分列未被索引。 -
索引選擇性較低(即重復值過多)。
-
5. 如何查看SQL語句的執行計劃(EXPLAIN)?
-
使用
EXPLAIN
查看SQL語句的執行計劃。
EXPLAIN SELECT * FROM table_name WHERE condition;
示例:查看查詢的執行計劃。
EXPLAIN SELECT * FROM employees WHERE department_id = 1;
關鍵字段解釋:
-
id
:查詢的序列號。 -
select_type
:查詢類型(簡單查詢、子查詢等)。 -
table
:操作的表名。 -
type
:訪問類型(ALL
表示全表掃描,index
表示索引掃描,ref
表示索引查找)。 -
key
:使用的索引名稱。 -
rows
:掃描的行數。 -
Extra
:附加信息(如是否使用臨時表、文件排序等)。
6. 什么是覆蓋索引(Covering Index)?
-
覆蓋索引:當查詢的所有列都在索引中時,無需回表查詢數據,直接從索引中獲取結果。
-
優點:避免回表操作,顯著提高查詢性能。
-
示例:假設有一個復合索引
(department_id, name)
,以下查詢可以使用覆蓋索引。
SELECT name FROM employees WHERE department_id = 1;
7. 什么是聚簇索引和非聚簇索引?
類型 | 描述 |
---|---|
聚簇索引 | 數據行按索引順序存儲在物理磁盤上,每個表只能有一個聚簇索引(通常是主鍵)。 |
非聚簇索引 | 索引存儲的是指向實際數據行的指針,數據行的存儲順序與索引無關。 |
8. 如何優化慢查詢?
-
優化方法:
-
分析慢查詢日志:啟用
slow_query_log
,找出執行時間較長的SQL語句。 -
添加索引:為頻繁查詢的列創建索引。
-
優化查詢語句:避免不必要的
SELECT *
,盡量只查詢需要的列。 -
減少鎖競爭:優化事務處理,減少鎖等待時間。
-
分區表:對大表進行分區,減少單次查詢的數據量。
-
緩存結果:使用查詢緩存或應用層緩存(如Redis)。
-
9. 什么是索引下推(Index Condition Pushdown)?
-
索引下推:MySQL的一種優化技術,在存儲引擎層面過濾掉不符合條件的記錄,減少回表次數。
-
適用場景:當查詢條件中包含非索引列時,存儲引擎可以直接利用索引過濾部分數據,而不是全部回表。
-
示例:假設有一個復合索引
(a, b)
,查詢條件為WHERE a = 1 AND b LIKE 'val%'
,索引下推允許存儲引擎直接過濾b LIKE 'val%'
的記錄。
10. 什么是回表查詢?
-
回表查詢:當查詢的列不在索引中時,需要通過索引找到主鍵值,再通過主鍵到聚簇索引中查找完整數據行。
-
原因:索引通常只包含部分列,而查詢可能需要更多列。
-
優化方法:盡量使用覆蓋索引,減少回表操作。
示例:假設有一個復合索引 (department_id, name)
,以下查詢會導致回表。
SELECT id, name, salary FROM employees WHERE department_id = 1;
因為 salary
不在索引中,必須回表查詢完整數據行。
四、事務與鎖
1. 什么是事務?事務的ACID特性是什么?
-
事務:一組邏輯操作單元,這些操作要么全部成功執行,要么全部不執行。
-
ACID特性:
-
Atomicity(原子性):事務是一個不可分割的工作單位,要么全部完成,要么全部失敗。
-
Consistency(一致性):事務執行前后,數據庫必須保持一致狀態。
-
Isolation(隔離性):多個事務并發執行時,彼此隔離,互不干擾。
-
Durability(持久性):事務一旦提交,其結果是永久性的,即使系統崩潰也不會丟失。
-
2. MySQL的默認事務隔離級別是什么?
-
MySQL默認隔離級別:
REPEATABLE READ
(可重復讀)。
3. 事務隔離級別有哪些?分別解決什么問題?
隔離級別 | 解決的問題 | 可能出現的問題 |
---|---|---|
READ UNCOMMITTED | 無 | 臟讀、不可重復讀、幻讀 |
READ COMMITTED | 解決臟讀 | 不可重復讀、幻讀 |
REPEATABLE READ | 解決臟讀和不可重復讀 | 幻讀 |
SERIALIZABLE | 解決所有并發問題 | 無 |
4. 什么是臟讀、不可重復讀、幻讀?
-
臟讀:一個事務讀取了另一個未提交事務的數據。
-
不可重復讀:一個事務在兩次查詢中讀取到的數據不一致(另一個事務修改并提交了數據)。
-
幻讀:一個事務在兩次查詢中發現多出了某些記錄(另一個事務插入了新記錄)。
5. 如何設置事務的隔離級別?
-
使用
SET TRANSACTION ISOLATION LEVEL
設置當前會話或全局的隔離級別。
-- 設置當前會話的隔離級別 SET TRANSACTION ISOLATION LEVEL 隔離級別;-- 設置全局隔離級別 SET GLOBAL TRANSACTION ISOLATION LEVEL 隔離級別;
示例:將隔離級別設置為 READ COMMITTED
。
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
6. 什么是共享鎖(S鎖)和排他鎖(X鎖)?
-
共享鎖(S鎖):允許多個事務同時讀取同一資源,但不允許寫入。
-
排他鎖(X鎖):獨占鎖,禁止其他事務讀取或寫入該資源。
7. 什么是死鎖?如何避免死鎖?
-
死鎖:兩個或多個事務互相等待對方釋放資源,導致所有事務都無法繼續執行。
-
避免死鎖的方法:
-
盡量減少事務的持有時間。
-
按固定的順序加鎖。
-
使用較低的隔離級別。
-
設置超時機制(如
innodb_lock_wait_timeout
)。
-
8. 什么是行級鎖和表級鎖?InnoDB支持哪種?
-
行級鎖:鎖定表中的特定行,允許多個事務同時操作不同的行。
-
表級鎖:鎖定整個表,阻止其他事務對該表的任何操作。
-
InnoDB支持:行級鎖(默認使用B-Tree索引實現)。
9. SELECT ... FOR UPDATE的作用是什么?
-
作用:對查詢的行加排他鎖(X鎖),防止其他事務修改或刪除這些行,直到當前事務提交或回滾。
-
適用場景:需要確保數據一致性時,例如銀行轉賬。
-
示例:
SELECT * FROM accounts WHERE id = 1 FOR UPDATE;
10. 什么是樂觀鎖和悲觀鎖?
-
樂觀鎖:假設沖突很少發生,因此不對數據加鎖,而是通過版本號或時間戳檢查數據是否被修改。如果發生沖突,則重新嘗試操作。
-
優點:性能高,適合低并發場景。
-
缺點:可能發生多次重試。
-
-
悲觀鎖:假設沖突經常發生,因此在操作前就對數據加鎖,防止其他事務修改。
-
優點:安全性高,適合高并發場景。
-
缺點:可能導致性能下降或死鎖。
-
示例:
-
樂觀鎖:通過版本號實現。
UPDATE accounts SET balance = balance - 100, version = version + 1 WHERE id = 1 AND version = 5;
-
悲觀鎖:使用
SELECT ... FOR UPDATE
實現。
五、存儲引擎
1. InnoDB和MyISAM的區別?
特性 | InnoDB | MyISAM |
---|---|---|
事務支持 | 支持事務 | 不支持事務 |
鎖機制 | 行級鎖 | 表級鎖 |
崩潰恢復 | 支持崩潰恢復 | 不支持崩潰恢復 |
外鍵支持 | 支持外鍵 | 不支持外鍵 |
存儲結構 | 數據和索引存儲在一起 | 數據和索引分開存儲 |
適用場景 | 高并發、需要事務的場景 | 讀密集型、簡單查詢場景 |
2. InnoDB為什么推薦使用自增主鍵?
-
原因:
-
性能優化:InnoDB使用聚簇索引(Clustered Index),數據按主鍵順序存儲。自增主鍵能夠保證插入時的順序性,避免頁分裂。
-
高效寫入:自增主鍵減少了隨機插入帶來的性能開銷。
-
唯一性:確保每行數據都有唯一的標識符。
-
3. MyISAM適合哪些場景?
-
適合場景:
-
以讀操作為主的場景。
-
數據量大但對事務無要求的場景。
-
全文索引搜索(MyISAM支持全文索引,而InnoDB在MySQL 5.6之前不支持)。
-
4. 如何查看和修改表的存儲引擎?
-
查看存儲引擎:
SHOW TABLE STATUS WHERE Name = 'table_name';
或:
SELECT ENGINE FROM information_schema.TABLES WHERE TABLE_NAME = 'table_name';
-
修改存儲引擎:
ALTER TABLE table_name ENGINE=新引擎;
示例:將表的存儲引擎改為InnoDB。
ALTER TABLE my_table ENGINE=InnoDB;
5. InnoDB的行鎖是如何實現的?
-
實現方式:
-
InnoDB通過B+樹索引來實現行鎖。
-
行鎖分為兩種:
-
記錄鎖(Record Lock):鎖定索引中的單個記錄。
-
間隙鎖(Gap Lock):鎖定索引中記錄之間的間隙,防止幻讀。
-
-
行鎖依賴于索引,如果查詢條件未命中索引,則會升級為表鎖。
-
六、表設計與范式
1. 什么是數據庫的三大范式?
-
第一范式(1NF):每個字段都是不可再分的原子值。
-
第二范式(2NF):在滿足1NF的基礎上,消除非主屬性對候選鍵的部分函數依賴。
-
第三范式(3NF):在滿足2NF的基礎上,消除非主屬性對候選鍵的傳遞函數依賴。
2. 什么是反范式化?什么時候需要反范式化?
-
反范式化:為了提高查詢效率,故意打破范式規則,增加冗余數據或重復存儲某些字段。
-
適用場景:
-
需要頻繁進行復雜聯表查詢的場景。
-
對讀性能要求高而對寫性能要求低的場景。
-
數據倉庫或報表系統中。
-
3. 如何設計一對多、多對多關系表?
-
一對多關系:
-
在“多”的一方添加外鍵指向“一”的一方。
-
示例:部門和員工(一個部門有多個員工)。
CREATE TABLE departments (id INT PRIMARY KEY,name VARCHAR(50) );CREATE TABLE employees (id INT PRIMARY KEY,name VARCHAR(50),department_id INT,FOREIGN KEY (department_id) REFERENCES departments(id) );
-
-
多對多關系:
-
創建一個中間表來存儲關聯關系。
-
示例:學生和課程(一個學生可以選多門課程,一門課程可以被多個學生選)。
CREATE TABLE students (id INT PRIMARY KEY,name VARCHAR(50) );CREATE TABLE courses (id INT PRIMARY KEY,name VARCHAR(50) );CREATE TABLE student_course (student_id INT,course_id INT,PRIMARY KEY (student_id, course_id),FOREIGN KEY (student_id) REFERENCES students(id),FOREIGN KEY (course_id) REFERENCES courses(id) );
-
4. 什么是雪花模型和星型模型?
-
星型模型:
-
中心是一個事實表,周圍是維度表。
-
簡單直觀,適合OLAP分析。
-
-
雪花模型:
-
在星型模型的基礎上進一步規范化,將維度表拆分為更小的子維度表。
-
更節省存儲空間,但查詢復雜度較高。
-
5. 如何設計一個支持軟刪除(邏輯刪除)的表?
-
方法:添加一個標記字段(如
is_deleted
或deleted_at
)來表示是否已刪除。 -
示例:
CREATE TABLE users (id INT PRIMARY KEY AUTO_INCREMENT,name VARCHAR(50),is_deleted TINYINT DEFAULT 0 COMMENT '0:未刪除, 1:已刪除',deleted_at DATETIME NULL COMMENT '刪除時間' );-- 查詢未刪除的用戶 SELECT * FROM users WHERE is_deleted = 0;-- 刪除用戶(邏輯刪除) UPDATE users SET is_deleted = 1, deleted_at = NOW() WHERE id = 1;
七、高級功能
1. 什么是存儲過程?優缺點是什么?
-
存儲過程:是一組預編譯的SQL語句,存儲在數據庫中,可以通過調用名稱執行。
-
優點:
-
提高性能(減少客戶端與服務器之間的通信)。
-
增強代碼復用性。
-
提高安全性(通過權限控制訪問)。
-
-
缺點:
-
調試困難。
-
可移植性差(不同數據庫的存儲過程語法可能不同)。
-
復雜邏輯難以維護。
-
2. 什么是觸發器?舉例說明。
-
觸發器:是一種特殊的存儲過程,當特定事件(如
INSERT
、UPDATE
或DELETE
)發生時自動執行。 -
示例:在插入新記錄時自動更新統計表。
CREATE TRIGGER after_insert_employee AFTER INSERT ON employees FOR EACH ROW BEGINUPDATE department_statsSET employee_count = employee_count + 1WHERE department_id = NEW.department_id; END;
3. 什么是視圖?視圖和表的區別?
-
視圖:是一個虛擬表,基于SQL查詢的結果集定義。視圖不存儲實際數據,而是從基礎表中動態生成。
-
視圖與表的區別:
特性 視圖 表 數據存儲 不存儲實際數據 存儲實際數據 更新能力 部分視圖可更新,復雜視圖不可更新 可更新 使用場景 簡化查詢、保護敏感數據 存儲原始數據
4. 如何實現數據庫的讀寫分離?
-
方法:
-
主庫負責寫操作,從庫負責讀操作。
-
使用主從復制技術同步數據。
-
在應用層或中間件(如ProxySQL、MaxScale)中實現讀寫分離。
-
-
示例:配置MySQL主從復制后,在應用中指定不同的連接地址。
// 寫操作連接主庫 $writeConnection = new PDO('mysql:host=master_host;dbname=test', 'user', 'password');// 讀操作連接從庫 $readConnection = new PDO('mysql:host=slave_host;dbname=test', 'user', 'password');
5. 什么是分區表?如何按范圍分區?
-
分區表:將一個大表的數據分成多個小塊存儲,每個塊稱為一個分區。
-
按范圍分區:根據某個字段的值范圍劃分分區。
-
示例:
CREATE TABLE sales (id INT,sale_date DATE,amount DECIMAL(10, 2) ) PARTITION BY RANGE (YEAR(sale_date)) (PARTITION p2020 VALUES LESS THAN (2021),PARTITION p2021 VALUES LESS THAN (2022),PARTITION p2022 VALUES LESS THAN (2023),PARTITION pfuture VALUES LESS THAN MAXVALUE );
八、備份與恢復
1. 邏輯備份和物理備份的區別?
特性 | 邏輯備份 | 物理備份 |
---|---|---|
備份內容 | SQL語句(建表語句、插入語句等) | 數據文件(如.ibd、.frm等) |
備份速度 | 較慢 | 較快 |
恢復速度 | 較慢 | 較快 |
可移植性 | 高 | 低 |
使用工具 | mysqldump | xtrabackup、直接復制文件 |
2. 如何用mysqldump備份數據庫?
-
備份整個數據庫:
mysqldump -u用戶名 -p密碼 數據庫名 > 備份文件.sql
-
備份多個數據庫:
mysqldump -u用戶名 -p密碼 --databases 數據庫1 數據庫2 > 備份文件.sql
-
備份所有數據庫:
mysqldump -u用戶名 -p密碼 --all-databases > 備份文件.sql
3. 什么是Binlog?它的作用是什么?
-
Binlog:二進制日志,記錄了數據庫的所有修改操作(如
INSERT
、UPDATE
、DELETE
)。 -
作用:
-
數據恢復:通過重放Binlog恢復誤刪除或損壞的數據。
-
主從復制:主庫將Binlog發送給從庫,從庫重放日志以保持數據一致性。
-
審計:記錄所有修改操作,便于追蹤問題。
-
4. 如何恢復誤刪除的數據?
-
方法:
-
使用最近的全量備份文件恢復到備份時間點。
-
使用Binlog恢復從備份時間點到誤刪除之前的操作。
-
-
示例:通過Binlog恢復數據。
mysqlbinlog binlog_file | mysql -u用戶名 -p密碼 數據庫名
5. 什么是主從復制?如何配置?
-
主從復制:將主庫的數據實時同步到從庫,用于讀寫分離、高可用性和災難恢復。
-
配置步驟:
-
主庫配置:
-
開啟Binlog:在
my.cnf
中設置log-bin=mysql-bin
。 -
設置服務器ID:
server-id=1
。 -
創建用于復制的用戶并授權。
-
-
從庫配置:
-
設置服務器ID:
server-id=2
。 -
執行
CHANGE MASTER TO
命令,指定主庫信息。 -
啟動復制:
START SLAVE;
。
-
-
-
示例:從庫配置主庫信息。
CHANGE MASTER TO MASTER_HOST='主庫IP', MASTER_USER='replication_user', MASTER_PASSWORD='password', MASTER_LOG_FILE='mysql-bin.000001', MASTER_LOG_POS=1234;
九、安全與權限
1. 如何創建用戶并授權?
-
創建用戶:
CREATE USER '用戶名'@'主機名' IDENTIFIED BY '密碼';
-
授權:
GRANT 權限列表 ON 數據庫名.表名 TO '用戶名'@'主機名';
示例:創建用戶并授予對特定數據庫的查詢權限。
CREATE USER 'testuser'@'localhost' IDENTIFIED BY 'password123'; GRANT SELECT ON mydb.* TO 'testuser'@'localhost';
2. GRANT和REVOKE的作用是什么?
-
GRANT:用于授予用戶權限。
GRANT 權限列表 ON 數據庫名.表名 TO '用戶名'@'主機名';
-
REVOKE:用于撤銷用戶權限。
REVOKE 權限列表 ON 數據庫名.表名 FROM '用戶名'@'主機名';
3. 如何防止SQL注入攻擊?
-
方法:
-
使用預處理語句(Prepared Statement)。
-
對用戶輸入進行嚴格校驗和轉義。
-
避免在SQL語句中直接拼接字符串。
-
4. 預處理語句(Prepared Statement)如何防止SQL注入?
-
預處理語句:將SQL語句和參數分開處理,避免惡意輸入被解析為SQL代碼。
-
示例(MySQLi擴展):
$stmt = $mysqli->prepare("SELECT * FROM users WHERE username = ? AND password = ?"); $stmt->bind_param("ss", $username, $password); $stmt->execute();
5. 如何限制用戶的登錄IP?
-
在創建用戶時指定允許登錄的主機地址。
CREATE USER '用戶名'@'指定IP' IDENTIFIED BY '密碼';
示例:只允許從192.168.1.100
登錄。
CREATE USER 'testuser'@'192.168.1.100' IDENTIFIED BY 'password123';
十、性能調優與監控
1. 如何開啟慢查詢日志?
-
步驟:
-
編輯MySQL配置文件
my.cnf
,添加或修改以下內容:slow_query_log = 1 slow_query_log_file = /var/log/mysql/slow-query.log long_query_time = 2 # 設置慢查詢閾值(秒)
-
重啟MySQL服務以使更改生效。
-
2. SHOW PROCESSLIST的作用是什么?
-
作用:顯示當前MySQL服務器上的線程信息,包括每個線程的狀態和執行的SQL語句。
-
示例:
SHOW PROCESSLIST;
-
常用字段:
-
Id
:線程ID。 -
User
:用戶名。 -
Host
:客戶端IP。 -
db
:當前使用的數據庫。 -
Command
:線程執行的操作類型。 -
Time
:線程運行時間。 -
State
:線程狀態。 -
Info
:執行的SQL語句。
-
3. 如何監控MySQL的QPS和TPS?
-
QPS(Queries Per Second):每秒查詢數。
-
TPS(Transactions Per Second):每秒事務數。
-
計算公式:
-
QPS = (Com_select + Com_insert + Com_update + Com_delete) / 時間間隔
-
TPS = (Com_commit + Com_rollback) / 時間間隔
-
-
示例:
SHOW GLOBAL STATUS LIKE 'Com_%';
4. 什么是連接池?為什么需要連接池?
-
連接池:一組預先創建好的數據庫連接,供應用程序重復使用,減少頻繁創建和銷毀連接的開銷。
-
優點:
-
提高性能:減少連接建立和斷開的時間。
-
控制資源:限制最大連接數,防止資源耗盡。
-
簡化管理:統一管理連接生命周期。
-
5. 如何優化大表查詢?
-
優化方法:
-
添加索引:為查詢條件中的列創建合適的索引。
-
分區表:將大表按某些字段分區,減少掃描的數據量。
-
分頁查詢:通過
LIMIT
和OFFSET
實現分頁查詢。 -
延遲加載:僅查詢必要的列,避免
SELECT *
。 -
緩存結果:對于不常變化的數據,使用應用層緩存(如Redis)。
-
水平拆分:將大表拆分為多個小表,分散數據壓力。
-
十一、JDBC與Java集成
1. JDBC連接MySQL的步驟是什么?
-
步驟:
-
加載驅動程序:通過
Class.forName()
加載MySQL驅動。Class.forName("com.mysql.cj.jdbc.Driver");
-
建立連接:使用
DriverManager.getConnection()
方法連接數據庫。Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/dbname", "username", "password");
-
執行SQL語句:創建
Statement
或PreparedStatement
對象,執行查詢或更新操作。 -
處理結果:如果執行的是查詢操作,使用
ResultSet
處理返回的結果。 -
關閉資源:關閉
ResultSet
、Statement
和Connection
。
-
2. Statement和PreparedStatement的區別?
特性 | Statement | PreparedStatement |
---|---|---|
SQL注入安全性 | 不安全(容易受到SQL注入攻擊) | 安全(防止SQL注入) |
性能 | 較低(每次都需要編譯SQL) | 較高(預編譯SQL) |
參數化支持 | 不支持 | 支持 |
3. 如何通過JDBC實現事務管理?
-
步驟:
-
禁用自動提交模式:
conn.setAutoCommit(false);
-
執行多個SQL操作。
-
如果所有操作成功,提交事務:
conn.commit();
-
如果發生異常,回滾事務:
conn.rollback();
-
最后恢復自動提交模式:
conn.setAutoCommit(true);
-
示例:
try {conn.setAutoCommit(false);// 執行SQL操作stmt.executeUpdate("INSERT INTO table_name ...");stmt.executeUpdate("UPDATE table_name ...");conn.commit(); } catch (SQLException e) {conn.rollback(); } finally {conn.setAutoCommit(true); }
4. 什么是數據庫連接泄漏?如何避免?
-
連接泄漏:指應用程序未正確關閉數據庫連接,導致連接被占用而無法釋放。
-
避免方法:
-
確保在
finally
塊中關閉所有資源(如ResultSet
、Statement
、Connection
)。 -
使用連接池管理數據庫連接。
-
使用
try-with-resources
語法(Java 7及以上)自動關閉資源。
-
5. 常用的JDBC連接池有哪些?(如HikariCP、Druid)
-
常用連接池:
-
HikariCP:高性能、輕量級的連接池,適合大多數場景。
-
Druid:阿里巴巴開源的連接池,功能豐富,支持監控和統計。
-
C3P0:老牌連接池,穩定但性能稍遜。
-
DBCP:Apache提供的連接池,但性能不如HikariCP和Druid。
-
十二、實戰應用題
1. 設計一個用戶表(包含字段:用戶ID、用戶名、注冊時間、最后登錄時間)。
CREATE TABLE users (user_id INT AUTO_INCREMENT PRIMARY KEY,username VARCHAR(50) NOT NULL UNIQUE,register_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,last_login_time DATETIME NULL );
2. 查詢每個部門薪資最高的員工(表:員工ID、部門ID、薪資)。
SELECT department_id, employee_id, salary FROM employees e1 WHERE salary = (SELECT MAX(salary)FROM employees e2WHERE e1.department_id = e2.department_id );
3. 如何實現樂觀鎖?(如版本號機制)
-
實現方式:
-
在表中添加一個
version
字段。 -
更新數據時,檢查當前版本號是否與預期一致。如果一致,則更新數據并將版本號加1;否則,拋出異常。
-
-
示例:
UPDATE employees SET salary = 8000, version = version + 1 WHERE employee_id = 1 AND version = 5;
4. 如何統計某張表的總行數?COUNT(*)和COUNT(1)的區別?
-
統計總行數:
SELECT COUNT(*) FROM table_name;
-
區別:
-
COUNT(*)
:統計所有行數,包括NULL值。 -
COUNT(1)
:等價于COUNT(*)
,通常用于優化器的性能測試。 -
結論:兩者在現代數據庫中幾乎沒有性能差異,推薦使用
COUNT(*)
以提高可讀性。
-
5. 如何刪除重復數據(保留一條)?
-
方法:使用臨時表或子查詢刪除重復數據。
-
示例:刪除
employees
表中重復的name
,保留一條。
DELETE FROM employees WHERE id NOT IN (SELECT MIN(id)FROM employeesGROUP BY name );
十三、場景分析題
1. 某查詢突然變慢,可能的原因是什么?
-
可能原因:
-
索引失效:查詢條件變化導致索引無法使用。
-
鎖等待:高并發場景下事務鎖導致阻塞。
-
表數據增長:數據量增大導致全表掃描耗時增加。
-
慢查詢日志未優化:復雜查詢未優化或缺少索引。
-
硬件資源不足:CPU、內存或磁盤I/O瓶頸。
-
主從同步延遲:讀取從庫時數據未及時更新。
-
2. 高并發場景下如何避免超賣問題?
-
方法:
-
庫存預扣:下單時先鎖定庫存,減少超賣風險。
-
分布式鎖:使用Redis等工具實現分布式鎖,確保同一商品的庫存操作互斥。
-
樂觀鎖:通過版本號或庫存字段進行CAS(Compare And Swap)操作。
-
隊列限流:將請求放入消息隊列處理,避免瞬間流量過大。
-
3. 如何設計一個點贊功能的數據庫表?
-
設計方案:
-
用戶表:存儲用戶信息。
CREATE TABLE users (user_id BIGINT AUTO_INCREMENT PRIMARY KEY,username VARCHAR(50) NOT NULL UNIQUE );
-
點贊表:記錄用戶對目標對象的點贊關系。
CREATE TABLE likes (like_id BIGINT AUTO_INCREMENT PRIMARY KEY,user_id BIGINT NOT NULL, -- 點贊用戶IDtarget_id BIGINT NOT NULL, -- 被點贊對象ID(如文章ID)target_type VARCHAR(20) NOT NULL, -- 被點贊對象類型(如"article"、"comment")created_at DATETIME DEFAULT CURRENT_TIMESTAMP,UNIQUE (user_id, target_id, target_type) );
-
4. 訂單表數據量過大,如何優化?
-
優化方法:
-
分區表:按時間范圍或訂單狀態分區,減少單次查詢的數據量。
-
水平拆分:將訂單表按某些字段(如用戶ID、地區)拆分為多個子表。
-
歸檔舊數據:將歷史訂單遷移到歸檔表或冷存儲中。
-
索引優化:為常用查詢字段添加合適的索引。
-
緩存熱點數據:使用Redis緩存高頻訪問的訂單信息。
-
5. 主從同步延遲導致數據不一致,如何解決?
-
解決方案:
-
優化SQL:減少大事務和復雜查詢,降低延遲。
-
半同步復制:啟用半同步復制,確保主庫寫入后從庫立即同步。
-
只讀從庫:避免在從庫上執行寫操作,防止沖突。
-
延遲復制:設置從庫延遲一段時間同步,便于恢復誤操作。
-
監控延遲:定期檢查主從延遲情況,及時發現問題。
-
十四、進階問題
1. 什么是MVCC(多版本并發控制)?
-
定義:MVCC是一種并發控制機制,允許事務讀取數據的“快照”,而無需加鎖。
-
工作原理:
-
每個事務都有一個唯一的事務ID。
-
數據行包含多個版本,每個版本標記創建和刪除的事務ID。
-
事務根據自己的ID判斷是否能看到某個版本的數據。
-
-
優點:
-
提高并發性能,減少鎖沖突。
-
支持可重復讀隔離級別。
-
2. InnoDB的Redo Log和Undo Log的作用?
-
Redo Log:
-
作用:記錄事務對數據頁的修改,用于崩潰恢復。
-
機制:事務提交前,先將修改寫入Redo Log,確保數據持久化。
-
-
Undo Log:
-
作用:記錄事務修改前的數據版本,用于回滾和MVCC。
-
機制:事務修改數據時,生成舊版本數據存入Undo Log,供其他事務讀取。
-
3. 什么是間隙鎖(Gap Lock)?
-
定義:間隙鎖鎖定索引中的間隙,防止其他事務插入新記錄。
-
作用:
-
防止幻讀(Phantom Read)。
-
在REPEATABLE READ隔離級別下自動啟用。
-
-
示例:
SELECT * FROM employees WHERE age BETWEEN 20 AND 30 FOR UPDATE;
-
上述查詢會鎖定
age
在20到30之間的所有間隙,防止其他事務插入符合條件的新記錄。
-
4. 什么是覆蓋索引(Covering Index)?
-
定義:當查詢的所有列都在索引中時,MySQL可以直接從索引中獲取結果,而無需回表查詢數據。
-
優點:減少IO操作,提高查詢性能。
-
示例:
CREATE INDEX idx_name_salary ON employees (name, salary);SELECT name, salary FROM employees WHERE name = 'Alice';
-
上述查詢可以完全依賴索引
idx_name_salary
,無需回表。
-
5. 如何實現分布式ID生成?(如雪花算法)
-
雪花算法(Snowflake):
-
原理:生成64位整數ID,結構如下:
-
1位:符號位(固定為0)。
-
41位:時間戳(毫秒級)。
-
10位:機器ID(區分不同服務器)。
-
12位:序列號(每毫秒內生成的序號)。
-
-
優點:
-
唯一性:結合時間戳和機器ID保證全局唯一。
-
高性能:無鎖操作,支持高并發。
-
-
實現方式:
-
使用開源庫(如Twitter Snowflake)。
-
自定義實現,分配機器ID并管理序列號。
-
-
十五、開放性問題
1. 你如何設計一個數據庫的索引策略?
-
設計原則:
-
分析查詢需求:根據常用查詢條件選擇合適的字段創建索引。
-
覆蓋索引:盡量使用覆蓋索引減少回表操作。
-
避免過度索引:過多索引會增加寫操作的開銷,需權衡讀寫性能。
-
復合索引:優先考慮使用復合索引(按查詢頻率和順序排列字段)。
-
定期優化:通過
EXPLAIN
分析查詢計劃,刪除無用索引。 -
唯一性約束:為需要保證唯一性的字段創建唯一索引。
-
2. 遇到過哪些MySQL性能問題?如何解決的?
-
常見問題及解決方法:
-
慢查詢:通過
slow_query_log
定位慢SQL,優化查詢語句或添加索引。 -
鎖等待:檢查死鎖日志,調整事務隔離級別或優化SQL邏輯。
-
主從延遲:優化大事務,啟用半同步復制或調整Binlog格式。
-
高內存使用:調整緩沖區大小(如
innodb_buffer_pool_size
),釋放無用連接。 -
IO瓶頸:使用SSD硬盤,優化Redo Log配置(如
innodb_flush_log_at_trx_commit
)。
-
3. 如何保證數據庫的高可用性?
-
方法:
-
主從復制:實現數據冗余,確保主庫故障時可以從庫接管。
-
雙主復制:兩個主庫互為主備,提高可用性。
-
分布式數據庫:使用分片技術分散數據壓力。
-
備份與恢復:定期全量備份,結合Binlog實現增量備份。
-
監控與告警:實時監控數據庫狀態,快速響應異常。
-
4. 分庫分表的常見方案有哪些?
-
分庫分表策略:
-
水平分片:按業務邏輯或數據特征(如用戶ID、地區)將數據分布到多個庫或表中。
-
哈希分片:使用哈希函數分配數據。
-
范圍分片:按時間范圍或數值區間劃分。
-
-
垂直分片:將不同業務模塊拆分到不同的數據庫中。
-
混合分片:結合水平和垂直分片,適應復雜場景。
-
5. 什么是CAP定理?MySQL如何取舍?
-
CAP定理:
-
C(一致性):所有節點數據一致。
-
A(可用性):每個請求都能收到非錯誤的響應。
-
P(分區容錯性):系統在部分節點失效時仍能正常運行。
-
結論:在一個分布式系統中,最多只能同時滿足兩個特性。
-
-
MySQL的取舍:
-
MySQL傾向于CP,即在分區容錯性和一致性之間權衡。
-
主從復制中,默認采用異步復制,犧牲部分可用性以保證一致性。
-
十六、壓軸難題
1. 什么是腦裂問題?如何避免?
-
腦裂問題:
-
在分布式系統中,當網絡分區發生時,集群中的節點可能無法感知彼此狀態,導致多個節點都認為自己是主節點。
-
-
避免方法:
-
仲裁機制:引入第三方仲裁器(如ZooKeeper),確保只有一個主節點。
-
多數派選舉:要求超過半數的節點同意才能選舉出主節點。
-
心跳檢測:定期檢查節點狀態,及時發現并隔離異常節點。
-
2. 如何實現跨庫事務(XA事務)?
-
XA事務:
-
是一種分布式事務協議,通過兩階段提交(Prepare和Commit)保證多庫操作的一致性。
-
-
實現步驟:
-
各個數據庫支持XA協議。
-
開啟事務:
XA START transaction_id
。 -
提交準備:
XA PREPARE transaction_id
。 -
確認提交:
XA COMMIT transaction_id
。 -
如果失敗,執行回滾:
XA ROLLBACK transaction_id
。
-
3. 什么是AP和CP的權衡?(如MySQL vs NoSQL)
-
AP系統(NoSQL):
-
強調可用性和分區容錯性,允許一定程度的數據不一致。
-
示例:MongoDB、Cassandra。
-
-
CP系統(MySQL):
-
強調一致性和分區容錯性,可能犧牲部分可用性。
-
示例:MySQL、PostgreSQL。
-
-
權衡:
-
AP適合高并發、弱一致性的場景(如社交應用)。
-
CP適合強一致性和事務需求高的場景(如金融系統)。
-
4. 如何設計一個支持千萬級數據量的訂單系統?
-
設計方案:
-
分庫分表:按用戶ID或訂單時間范圍進行分片。
-
分布式ID生成:使用雪花算法生成全局唯一訂單ID。
-
緩存熱點數據:使用Redis緩存高頻訪問的訂單信息。
-
異步處理:將訂單創建、支付等操作放入消息隊列,減少數據庫壓力。
-
歸檔舊數據:定期將歷史訂單遷移到冷存儲中。
-
讀寫分離:通過主從復制實現讀寫分離,提升查詢性能。
-
5. MySQL 8.0有哪些新特性?
-
主要特性:
-
窗口函數:支持
OVER()
子句,便于復雜數據分析。 -
Common Table Expressions (CTE):支持遞歸查詢。
-
JSON增強:提供更多JSON操作函數。
-
不可見索引:允許臨時禁用索引而不刪除。
-
角色管理:簡化權限管理。
-
改進的優化器:更高效的查詢計劃。
-
數據字典:使用InnoDB存儲元數據,提高可靠性。
-