數據庫分類
列式數據庫 | 按列存儲,方便查找,但是隨着內存和SSD壓縮列所佔百分比的提高,它也可以用來事務處理和數據更新。適合大量數據。 優點: 1.極高的裝載速度 (最高可以等於所有硬盤IO 的總和) 2.適合大量的數據而不是小數據 3.高效的壓縮率,不僅節省儲存空間也節省計算內存和CPU. 4.非常適合做聚合操作 缺點: 1.不適合隨機更新 2.不適合含有刪除和更新的實時操作 |
---|---|
行式數據庫 | 按行存儲,便於事務處理 |
安裝
下載
https://downloads.mysql.com/archives/community/
選擇你需要的版本,下載源碼,編譯安裝
安裝
存儲引擎對比
MyISAM | InnoDB | NDBCluster |
---|---|---|
特點: | ||
1.不支持事務 2.表級鎖定,限制了併發 3.讀寫互相阻塞(即讀取時阻塞寫,寫時阻塞讀) 4.只會用key_buffer緩存索引 |
1.支持4個事務隔離級別 2.行級鎖定 3.讀寫阻塞與事務隔離級別相關 4.高效緩存,整個表和主鍵以cluster方式存儲,組成一顆平衡樹 |
1.分佈式存儲引擎,存儲整體中的部分數據 2.支持事務 3.內存需求巨大 |
適用場合: | ||
1.不需要支持事務 2.併發相對較低 3.數據修改較少 4.以讀爲主 5.數據一致性要求不是非常高 對於相對靜態的數據,利用query cache可以極大提高訪問效率 |
1.事務支持 2.高併發支持,但注意查詢用索引 3.數據更新較爲頻繁 4.數據一致性要求高 避免全表掃描 大數據插入自己控制事務 避免主鍵更新 |
1.非常高併發需求 2.對單個請求響應不嚴格 3.查詢簡單,過濾條件較爲固定 |
服務操作
服務開啓、關閉、重啓、查看狀態
Mysql.server start/restart/stop/status
Mysql.server
文件安裝時在安裝目錄下可以找到
查看Mysql服務
ps -ef |grep mysql
連接
連接
安裝後,第一次連接不需要密碼,直接回車就進去了。
mysql -u root -p
輸入之後回車,再回車。設置密碼之後第一次回車之後輸入密碼即可。
進入指定庫:
mysql -u root -p dbname
退出
exit
、quit
幫助命令
進入命令行輸入help或者? + command即可查看對應語法。
舉例:
mysql> help select;
或者
mysql> ? select;
用戶管理
用戶
添加
命令格式:
CREATE USER 'username'@'host' IDENTIFIED BY 'password';
host一般爲%代替匹配任何字符
重命名
rename USER user to user1
刪除用戶
drop user user1
密碼
設置密碼
-
命令行設置
mysqladmin -u root password "123456"
這個命令在mysql安裝目錄的bin目錄下,最好將這個目錄設置到環境變量path中 -
進入mysql設置
use mysql;
說明使用那個數據庫root用戶:
SET PASSWORD = PASSWORD('biscuit');
指定用戶:
SET PASSWORD FOR 'jeffrey'@'%' = PASSWORD('biscuit');
修改密碼
更新已有賬戶密碼:
UPDATE user SET Password = PASSWORD('bagel') WHERE Host = '%' AND User = 'francis';
權限
授權
命令格式:
GRANT ALL PRIVILEGES ON *.*(庫.表) TO 'backlion'(用戶)@'%'(地址,%爲匹配符) IDENTIFIED BY 'backlion123'(密碼) WITH GRANT OPTION;
括號裏面是說明,實際不寫括號
被授權用戶不能再授權,如果想,則需要在授權命令末尾加上 WITH GRANT OPTION
查看指定用戶權限
show grants for user1
撤銷權限
撤銷某個表的部分權限:
REVOKE all privilege(select,update,delete,insert) ON dbname.tablename FROM 'username'@'host';
撤銷所有權限:
revoke ALL PRIVILEGES on *.* from user1
重新載入授權表
FLUSH PRIVILEGES
數據庫操作
常用命令
– | – |
---|---|
查看數據庫狀態 | mysql> status; |
查看編碼 | mysql> show variables like 'char%'; |
修改編碼 | alter database db_name CHARACTER SET utf8; |
顯示數據庫當前狀態 | show status; |
顯示線程表 | show processlist; |
查看mysql提供引擎 | show engines; |
看當前默認的存儲引擎 | show variables like '%storage_engine%'; |
修改表引擎 | alter table table_name engine=innodb; |
查詢當前sql模式 | SELECT @@sql_mode |
殺死對應線程id | KILL thread_id; |
庫
創建庫
create database dbname default character set utf8mb4 collate utf8_general_ci;
使用庫
use dbname;
修改庫
重命名:
rename database oldname to newname;
修改字符集:
alter database character set utf8mb4;
刪除庫
drop database IF EXISTS dbname;
查看庫
顯示所有庫:
show databases;
查看創建庫的sql語句:
show create database test;
表
列類型
創建表
CREATE TABLE IF NOT EXISTS `person` (
`number` int(11) DEFAULT NULL AUTO_INCREMENT COMMENT '機器ID',
`name` varchar(255) DEFAULT NULL,
`birthday` date DEFAULT NULL
PRIMARY KEY (number),--------主鍵
UNIQUE KEY `unique_fname_lname` (`fisrtname`,`lastname`),
KEY `fname_lname_age` (`firstname`,`lastname`,`age`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
創建臨時表:
CREATE TEMPORARY TABLE table_name();
舉例:
create temporary table student_copy(
id int primary key,
name varchar(20)
)Engine=InnoDB default charset utf8;
臨時表只對當前連接有效。
修改表
修改表的引擎:
alter table tableName engine=innodb;
修改表的字符集:
alter table tableName convert to character set utf8mb4;
移動表到其他數據庫:
rename TABLE current_db.tbl_name TO other_db.tbl_name;
重命名錶:
rename table 原表名 to 新表名;
修改表字段:
增:
alter table table1 add transactor varchar(10) not Null;
刪:
alter table table_name drop column 字段名;
改:
alter table 表名稱 change 舊名稱 新名稱 字段類型 [是否允許非空]; #修改字段名
alter table 表名稱 modify 字段名 字段類型 [是否允許非空]; #修改字段其他屬性
刪除表
刪除指定表:
drop table table_name;
刪除數據庫中的所有表:
select concat('drop table ',table_name,';') from TABLES where table_schema='dbname';
查看錶
show tables;
顯示所有列信息:
desc tableName;
刪除表中的數據
delete from table1;
範圍刪除,之後插入id不會從1開始
truncate table table1;
清空表,索引從1開始
SELECT
語法
SELECT
[ALL | DISTINCT | DISTINCTROW ]
[HIGH_PRIORITY]
[MAX_STATEMENT_TIME = N]
[STRAIGHT_JOIN]
[SQL_SMALL_RESULT] [SQL_BIG_RESULT] [SQL_BUFFER_RESULT]
[SQL_CACHE | SQL_NO_CACHE] [SQL_CALC_FOUND_ROWS]
select_expr [, select_expr ...]
[FROM table_references
[PARTITION partition_list]
[WHERE where_condition]
[GROUP BY {col_name | expr | position}
[ASC | DESC], ... [WITH ROLLUP]]
[HAVING where_condition]
[ORDER BY {col_name | expr | position}
[ASC | DESC], ...]
[LIMIT {[offset,] row_count | row_count OFFSET offset}]
[PROCEDURE procedure_name(argument_list)]
[INTO OUTFILE 'file_name'
[CHARACTER SET charset_name]
export_options
| INTO DUMPFILE 'file_name'
| INTO var_name [, var_name]]
[FOR UPDATE | LOCK IN SHARE MODE]]
單表查詢
舉例:
where:
select id, tag_name from test where id = 22
GROUP BY:
HAVING子句可以引用總計函數,而WHERE子句不能引用
SELECT user, MAX(salary) FROM users GROUP BY user HAVING MAX(salary)>10;
LIMIT分頁:
SELECT * FROM tbl LIMIT 5,10; # Retrieve rows 6-15; 從索引5開始找10個數據
INTO OUTFILE查詢結果寫入服務器文件:
SELECT a,b,a+b INTO OUTFILE '/tmp/result.text'
FIELDS TERMINATED BY ','
OPTIONALLY ENCLOSED BY '"'
LINES TERMINATED BY '\n'
FROM test_table;
UNION:將多個查詢結果放到一個結果集中
SELECT ...
UNION [ALL | DISTINCT]
SELECT ...
[UNION [ALL | DISTINCT]
SELECT ...]
ORDER BY排序:
ASC
(升序,默認)
DESC
(降序)
多表查詢
join
- 內連接:inner join,笛卡爾積匹配;
- 左連接:left join,右表匹配左表
- 右連接:right join,左表匹配右表
舉例:
SELECT * from facts t1 LEFT JOIN oper_log t2 ON t1.id=t2.id;
一般不會三個不同連接一起使用
INSERT
語法
INSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE]
[INTO] tbl_name
[PARTITION (partition_name,...)]
[(col_name,...)]
{VALUES | VALUE} ({expr | DEFAULT},...),(...),...
[ ON DUPLICATE KEY UPDATE
col_name=expr
[, col_name=expr] ... ]
Or:
INSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE]
[INTO] tbl_name
[PARTITION (partition_name,...)]
SET col_name={expr | DEFAULT}, ...
[ ON DUPLICATE KEY UPDATE
col_name=expr
[, col_name=expr] ... ]
Or:
INSERT [LOW_PRIORITY | HIGH_PRIORITY] [IGNORE]
[INTO] tbl_name
[PARTITION (partition_name,...)]
[(col_name,...)]
SELECT ...
[ ON DUPLICATE KEY UPDATE
col_name=expr
[, col_name=expr] ... ]
舉例
批量插入
INSERT INTO oper_log(oper_name, oper_detail) VALUES("admin1", "insert data"),("admin2", "insert data");
插入時存在更新
這種情況必須存在主鍵或者唯一索引,否則直接插入
insert into record_detail (logid, detail) VALUES (2,'bob2'),(3,'bob3') on DUPLICATE KEY UPDATE detail = VALUES(detail);
或者:
1. replace into tbl_name(col_name, ...) values(...)
2. replace into tbl_name(col_name, ...) select ...
3. replace into tbl_name set col_name=value, ...
使用查詢結果插入
insert into tablename (id, col_name) select id, col_name from t_table where 1=1;
UPDATE
語法
Single-table syntax:
UPDATE [LOW_PRIORITY] [IGNORE] table_reference
SET col_name1={expr1|DEFAULT} [, col_name2={expr2|DEFAULT}] ...
[WHERE where_condition]
[ORDER BY ...]
[LIMIT row_count]
Multiple-table syntax:
UPDATE [LOW_PRIORITY] [IGNORE] table_references
SET col_name1={expr1|DEFAULT} [, col_name2={expr2|DEFAULT}] ...
[WHERE where_condition]
舉例
多表聯合更新:
UPDATE record_detail t1 LEFT JOIN oper_log t2 ON t1.logid=t2.id SET t1.detail = t2.oper_detail WHERE t2.oper_name = '用戶2';
一般不建議使用多表關聯更新
單表更新:
UPDATE record_detail SET detail = 'update data' WHERE id = 1;
DELETE
語法
Single-Table Syntax
DELETE [LOW_PRIORITY] [QUICK] [IGNORE] FROM tbl_name
[PARTITION (partition_name,...)]
[WHERE where_condition]
[ORDER BY ...]
[LIMIT row_count]
Multiple-Table Syntax
DELETE [LOW_PRIORITY] [QUICK] [IGNORE]
tbl_name[.*] [, tbl_name[.*]] ...
FROM table_references
[WHERE where_condition]
Or:
DELETE [LOW_PRIORITY] [QUICK] [IGNORE]
FROM tbl_name[.*] [, tbl_name[.*]] ...
USING table_references
[WHERE where_condition]
舉例
單表刪除
delete from record_detail WHERE id = 1;
多表刪除
delete t1, t2 from record_detail t1 LEFT JOIN oper_log t2 on t1.logid=t2.id WHERE t2.id = 6;
函數
類型轉換
SELECT CAST(logid as char) FROM record_detail;
SELECT CONVERT(logid, char) FROM record_detail;
可轉換的類型:
BINARY[(N)]
CHAR[(N)]
DATE
DATETIME
DECIMAL
SIGNED [INTEGER]
TIME
UNSIGNED [INTEGER]
數學運算
mysql> select abs(-8);
##絕對值
±--------+
| abs(-8) |
±--------+
| 8 |
±--------+
mysql>select ceiling(9.4);
##向上取整
±-------------+
| ceiling(9.4) |
±-------------+
| 10 |
±-------------+
mysql> select floor(3.4);
##向下取整
±-----------+
| floor(3.4) |
±-----------+
| 3 |
±-----------+
mysql> select rand();
##返回0–1的隨機數
±-------------------+
| rand() |
±-------------------+
| 0.7959931481592293 |
±-------------------+
字符串函數
mysql> select char_length('length');
##計算字符串長度
±----------------------+
| char_length(‘length’) |
±----------------------+
| 6 |
±----------------------+
mysql> select concat('aaa','bbb','ccc');
##拼接字符串
±--------------------------+
| concat(‘aaa’,‘bbb’,‘ccc’) |
±--------------------------+
| aaabbbccc |
±--------------------------+
mysql> selectinsert('abcdefghijk', 2,4,'xxxxxxxx');
##具體位置插入字符串替代幾個字符,也可作爲替換使用。說明:從第2個位置開始的4個字符刪除,用後面的字符串替換。
±--------------------------------------+
| insert(‘abcdefghijk’, 2,4,‘xxxxxxxx’) |
±--------------------------------------+
| axxxxxxxxfghijk |
±--------------------------------------+
mysql>select lower('ABCDEF');
##大寫轉小寫 upper():小寫轉大寫
±----------------+
| lower(‘ABCDEF’) |
±----------------+
| abcdef |
±----------------+
mysql> select instr('abcdefgh', 'g');
##查找第一個出現的位置
±-----------------------+
| instr(‘abcdefgh’, ‘g’) |
±-----------------------+
| 7 |
±-----------------------+
mysql> select substr('abcdefghi',3,2);
##獲取從某個位置開始長度爲n的字串
±------------------------+
| substr(‘abcdefghi’,3,2) |
±------------------------+
| cd |
±------------------------+
mysql> select replace('abcdefghijk','j','xx');
##字符串替換
±--------------------------------+
| replace(‘abcdefghijk’,‘j’,‘xx’) |
±--------------------------------+
| abcdefghixxk |
±--------------------------------+
時間函數
時間獲取
mysql> select curdate();
##當前日期
±-----------+
| curdate() |
±-----------+
| 2020-04-26 |
±-----------+
mysql> select now();
##當前時間
±--------------------+
| now() |
±--------------------+
| 2020-04-26 09:14:12 |
±--------------------+
mysql> select year(NOW());
##獲取當前時間的年,month,day,hour,minute,second
±------------+
| year(NOW()) |
±------------+
| 2020 |
±------------+
日期和天數轉換
SELECT TO_DAYS(NOW()); -- 737908
SELECT FROM_DAYS(737908); -- 2020-04-28
時間和秒數轉換
SELECT TIME_TO_SEC(NOW()); -- 56744
SELECT SEC_TO_TIME(56609); -- 15:43:29
時間拼湊
SELECT MAKETIME(2,3,5); -- 02:03:05
SELECT MAKEDATE(2021,300); -- 2021-10-27
日期計算
– HOUR,MINUTE,SECOND,WEEK,MONTH,YEAR
SELECT DATE_ADD(NOW(), INTERVAL 1 DAY); -- 加一天
SELECT DATE_SUB(NOW(), INTERVAL 1 QUARTER); -- 減三個月
時間差
SELECT DATEDIFF('2008-12-30','2008-12-29'); --1
SELECT TIMEDIFF('15:45:44','15:47:44'); -- 00:02:00
時區轉換
select convert_tz('2008-08-08 12:00:00', '+08:00', '+00:00'); -- 2008-08-08 04:00:00
聚合函數
函數 | 說明 |
---|---|
count() | 計算個數,count(字段):會忽略所有的null;count(*)與count(1)區別:1只查一列,二者不會忽略null列 |
sum() | 求和 |
avg() | 平均分 |
max() | 最高分 |
min() | 最低分 |
數據庫級別MD5加密
mysql>select md5('22222');
##加密
±---------------------------------+
| md5(‘22222’) |
±---------------------------------+
| 3d2172418ce305c7d16d4b05597c6a59 |
±---------------------------------+
事務
原則
原子性(A)
一致性©
隔離性(I)
髒讀
事務A讀取了事務B更新的數據,然後B回滾操作,那麼A讀取到的數據是髒數據
幻讀
系統管理員A將數據庫中所有學生的成績從具體分數改爲ABCDE等級,但是系統管理員B就在這個時候插入了一條具體分數的記錄,當系統管理員A修改結束後發現還有一條記錄沒有改過來,就好像發生了幻覺一樣,這就叫幻讀。
不可重複讀
事務 A 多次讀取同一數據,事務 B 在事務A多次讀取的過程中,對數據作了更新並提交,導致事務A多次讀取同一數據時,結果 不一致。
總結
不可重複讀的和幻讀很容易混淆,不可重複讀側重於修改,幻讀側重於新增或刪除。
解決不可重複讀的問題只需鎖住滿足條件的行,解決幻讀需要鎖表
持久性(D)
#設置是否自動提交事務,默認自動提交
#關閉自動提交
set autocommit = 0;
#開啓事務
start TRANSACTION
#操作
insert
insert
#提交
COMMIT
#回滾
ROLLBACK
#開啓自動提交
set autocommit = 1;
索引
快速獲取數據庫中的數據
分類
-
主鍵索引(PRIMARY KEY)
不可重複
-
唯一索引(UNIQUE KEY)
避免重複的列出現,唯一索引可以重複,多個列都可以標識爲唯一索引
-
常規索引(KEY/INDEX)
默認的,index和key設置
-
全文索引(FullText)
快速定位數據,myisam引擎下有效
操作
增
Syntax:
CREATE [UNIQUE|FULLTEXT|SPATIAL] INDEX index_name
[index_type]
ON tbl_name (index_col_name,...)
[index_option]
[algorithm_option | lock_option] ...
示例:
create index index_name on test(col_name);
說明:
1.只有當正在使用MyISAM, BDB或InnoDB表類型時,可以向BLOB(二進制流)或TEXT列中添加索引,也可以向有NULL值的列中添加索引
2.FULLTEXT索引只能對CHAR, VARCHAR和TEXT列編制索引,並且只能在MyISAM表中編制。
3.SPATIAL索引只能對空間列編制索引,並且只能在MyISAM表中編
刪
alter table table_name Drop index index_name;
drop index index_name on table_name;
刪除主鍵索引:
alter table table_name drop primary key;
改
添加主鍵索引:
alter table table_name add primary key(id);
添加唯一索引:
alter table table_name add unique name_unique_index (col_name);
添加普通索引:
alter table table_name add index index_name (col_name);
禁用/激活非唯一索引:
alter table table_name disable | enable keys;
查
show index from table_name;
批量插入
-- 寫函數之前必須要寫的標誌,避免語句總有分號直接停止後續語句的執行
DELIMITER $$
create FUNCTION mock_data() -- 函數名
RETURNS INT -- 返回值
BEGIN -- 函數體
-- 變量名
DECLARE num int DEFAULT 1000000;
declare i int default 0;
-- 開啓循環
while i < num do
-- 執行的語句
insert into oper_log(oper_name,oper_detail) values (CONCAT('用戶',i),CONCAT('{\"json1\":',i,'}'));
set i = i+1;
end while;
return i;
END;
#執行函數
SELECT mock_data();
#刪除函數
DROP PROCEDURE mock_data;
索引使用原則
- where 子句或者join子句中出現的列
分析SQL效率
explain
mysql> explain select * from facts;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------+
| 1 | SIMPLE | facts | NULL | ALL | NULL | NULL | NULL | NULL | 1 | 100.00 | NULL |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------+
結果顯示說明:
table:這是表的名字。
type:連接操作的類型。匹配行數,最好顯示const,all最差
possible_keys:可能可以利用的索引的名字
Key:MySQL實際使用的索引的名字
key_len:索引中被使用部分的長度,以字節計
rows:MySQL所認爲的它在找到正確的結果之前必須掃描的記錄數
分析慢查詢sql
show variables like '%slow_query_log%';
查看慢查詢是否開啓和日誌保存路徑
配置
slow_query_log = 1
slow_query_log_file = /tmp/mysql_slow.log
#查詢閾值,大於這個值記錄到日誌
long_query_time = 10
使用工具分析慢查詢日誌
mysqldumpslow -s r -t 10 /usr/local/mysql/data/slow.log
命令說明:
-s | 自定義按那種排序方式輸出結果 c:總次數 t:總時間 l:鎖的時間 r:總行數 at,al,ar:平均數的意思 |
---|---|
-t | 指定取前幾條數據 |
備份
歸檔模式與非歸檔模式對比
歸檔模式 | 非歸檔模式 |
---|---|
做熱備份,並且可以做增量備份,可以做部分恢復 | 非歸檔就是不保存舊事務日誌 只能做冷備份,並且恢復時只能做完全備份.最近一次完全備份到系統出錯期間的數據不能恢復. |
冷熱備份
對比 | 冷備份 | 熱備份 |
---|---|---|
指在數據庫關閉後,進行備份,適用於所有模式的數據庫 | 針對歸檔模式的數據庫,在數據庫仍舊處於工作狀態時進行備份 |
數據庫使用歸檔方式運行時纔可以進行災難性恢復
如果數據庫處於非歸檔模式,聯機日誌在切換時就會丟棄. 而在歸檔模式下,當發生日誌切換的時候,被切換的日誌會進行歸檔
導出數據庫
導出表結構
mysql的bin目錄找到mysqldump:
mysqldump -u 用戶名 -p 密碼 -d 數據庫名 > 數據庫名.sql
導出數據和表結構,包含存儲過程、函數
mysqldump -u 用戶名 -p 密碼 -R -d 數據庫名 > 數據庫名.sql
具體其他參數,可以使用 ./mysqldump --help
查看
導入數據庫
導入前需要確定數據庫是否存在。
如果數據庫名包含符號,使用反引號將庫名包裹起來。
命令行
mysql -u用戶名 -p密碼 數據庫名 < 數據庫名.sql
Mysql命令行:
use DbName;
source /home/abc/abc.sql;
#這裏是sql文件的絕對路徑
動態備份
基於mysqldump通常就是:完整備份 + 二進制日誌 來進行恢復
https://www.cnblogs.com/xsuid/archive/2018/08/03/9416593.html
數據庫設計
三大範式
第一範式
每張表的每列都是不可再分的。列的原子性。
第二範式
前提
滿足第一範式
每一列都和主鍵相關(針對聯合主鍵而言)
即一個表只描述一件事情。
第三範式
前提
滿足第二範式
消除傳遞依賴
命名
- 庫名(可以顯示項目信息),表名(顯示功能),字段(合理使用字段類型,字段命名可以查看功能,非負使用unsigned,範圍小使用tinyint),單條記錄最好不超過8K
- myisam:建議使用國定長度的數據列代替可變長度。
- 能用tinyint就不用integer
- 如果需要使用小數嚴謹使用float,double,使用定點數decimal,decimal實際上是以字符串的形式存儲的(但是會佔用更多的存儲空間),所以更加精確,java中與之對應的數據類型爲BigDecimal
- 對於金額直接使用bigint存儲
- tinyint(2),對於整型來說小括號中的2不是指的存儲長度,而是指的零填充達到長度2
分表
單錶行數超過500萬行或者單表容量超過 2GB,才推薦進行分庫分表
分區
將數據庫的表分割成多個表,當然看到的還是一個表,只不過物理保存的時候是多個文件。使用分區的前提是表是獨立空間存儲的。
可以在建表時分區,也可以在之後分區。
舉例:
create table emp_date(
id int not null,
separated date not null default '9999-12-31'
)
#以某個字段分區
partition by range columns(separated) (
partiontion p0 values less than ('1990-01-01'),
partiontion p0 values less than ('2001-01-01'),
partiontion p0 values less than ('2018-01-01')
);
數據切分
水平切分 | 垂直切分 |
---|---|
定義: | |
按照一定規則切分單個表 | 根據功能模塊分類多個表 |
特點: | |
◆ 數據庫的拆分簡單明瞭,拆分規則明確; ◆ 應用程序模塊清晰明確,整合容易; ◆ 數據維護方便易行,容易定位; | ◆ 表關聯基本能夠在數據庫端全部完成; ◆ 不會存在某些超大型數據量和高負載的表遇到瓶頸的問題; ◆ 應用程序端整體架構改動相對較少; ◆ 事務處理相對簡單; ◆ 只要切分規則能夠定義好,基本上較難遇到擴展性限制; |
缺點: | |
◆ 部分表關聯無法在數據庫級別完成,需要在程序中完成; ◆ 對於訪問極其頻繁且數據量超大的表仍然存在性能平靜,不一定能滿足要求; ◆ 事務處理相對更爲複雜; ◆ 切分達到一定程度之後,擴展性會遇到限制; ◆ 過讀切分可能會帶來系統過渡複雜而難以維護。 | ◆ 切分規則相對更爲複雜,很難抽象出一個能夠滿足整個數據庫的切分規則; ◆ 後期數據的維護難度有所增加,人爲手工定位數據更困難 ◆ 應用系統各模塊耦合度較高,可能會對後面數據的遷移拆分造成一定的困難。 |
整合方案:自行編寫中間代理層 | 使用開源框架: AmoebaForMySQL:只能是mysql協議連接與數據源 AmoebaForAladin:mysql協議連接,可以多種數據源 HiveDB:只支持水平切分, |
切分和整個之後問題: | |
分佈式事務問題:可以在應用解決爲單一數據源 跨節點join問題:可由應用解決,通過查詢驅動 跨節點合併排序分頁問題:可由應用解決 |
注意:
實際設計時需要根據實際業務需求設計。
數據庫優化
有哪些優化方面:
字段類型、分表存儲、事務處理、數據庫參數優化(最大連接、佔用內存等)、讀寫分離(主從複製)、增加緩存(redis, memcached等)、升級硬件設備(磁盤IO讀寫速度,CPU,內存,帶寬)
SQL優化
-
GROUP BY NULL
禁止排序避免對結果排序的消耗 -
ORDER BY
使用索引 -
INSERT
插入多行使用values一次插入,不要多次插入 -
INSERT DELAYED
多個連接同時插入時,使用延遲插入提高插入速度 -
如果只是查詢,設置配置mysql的low_priority_updates=1,降低寫的優先級
-
大量數據操作時分批操作,這樣不會導致一個線程佔用表太長時間
-
不要在where條件表達式寫計算表達式,儘量少使用函數對字段操作,這樣會導致不會使用索引。簡單判斷即可
-
對以下操作符才使用索引:
<,<=,=,>,>=,BETWEEN,IN,以及某些時候的LIKE。
不要寫==!=,<>==,用between或者> and < 代替 -
少用子查詢,使用連接(JOIN)來代替子查詢(Sub-Queries)
-
where 條件中不要使用 or(導致全表掃描),使用聯合替代
舉例:
select id from t where num=10 or Name = 'admin' 替換: select id from t where num = 10 union all select id from t where Name = 'admin'
-
in 和not in最好別用,容易導致全表掃描,一些情況下,可以使用exists替換in。
使用exists先查詢主表,再與子查詢作對比;
in先查詢子查詢,在和主表笛卡爾。
如果子查詢記錄多,用exists;如果子查詢少,用in -
最好不要使用like ’ ', 全表掃描
-
字段儘量設置爲not null
-
or只有兩邊都是索引才使用索引
-
查詢時字段類型要正確,否則不使用索引
-
模糊查詢只有最前綴使用索引,即%在後面匹配
-
使用連接(JOIN)來代替子查詢(Sub-Queries)
JDBC
對數據庫使用統一接口
代碼實現步驟
-
註冊Driver
Class.forName("com.mysql.jdbc.Driver");
-
連接數據庫
//用戶與連接信息 String url = "jdbc:mysql://localhost:3306/dbname?useUnicode=true&characterEncoding=utf8&useSSL=true"; String username = "root"; String password = "123456" //連接獲取connection Connection connection = DriverManager.getConnect(url, username, password); //獲取執行對象 Statement statement = connection.createStatement();
-
操作數據庫
//sql 語句 String sql = "SELECT * from test"; //執行sql ResultSet resultSet = statement.executeQuery(sql); //訪問結果,具體方法查看對應類或者使用時.選擇對應函數 resultSet.getObject("columnName");
-
關閉資源
resultSet.close(); statement.close(); connection.close();
SQL注入
參數沒有處理導致注入sql,實現非法操作
'or 1=1'
PreparedStatement
對象防止sql注入
連接池
druid
阿里提供的數據庫連接池
C3P0
xml配置參數
DBCP
需要jar包
commons-dbcp-1.4
commons-pool-1.6
FAQ
mysql啓動出現錯誤
mysql.sock 文件丟失
或者
Manager of pid-file quit without updating file.[FAILED]
方法:
/usr/local/bin/mysql_install_db
忘記密碼
方法一:
修改配置文件my.conf,添加skip-grant-tables
重啓mysql並登陸(無密碼)
修改mysql數據庫中root用戶密碼
update user set authentication_string=password('123456') where user='root';
刷新權限:
flush privileges;
退出,刪除配置文件中添加項
方法二:
不檢查權限方式啓動
mysql -u root -p --skip-grant-tables &(可加選項)
登陸修改密碼即可
update MySQL.user set password=PASSWORD('newpassword') where User='root';
flush privileges;
字段中存在引號
數據庫插入字段中包含單引號,只需要將單引號替換爲雙引號即可。
刪除表中重複字段,保留一個
DELETE from t_entity_terminal WHERE termid in(SELECT termid from (SELECT max(termid) as termid from t_entity_terminal GROUP BY machinesid HAVING COUNT(machinesid) > 1) as tmpresult);
需要建立臨時表,否則刪除不成功
數據庫表crash修復
1.關閉mysql服務
2.myisamchk -f -o tablename.MYI
或者
檢查
mysqlcheck -u root -p wordpress
備份
mysqldump -u root -p wordpress > wordpress.sql
修復
mysqlcheck -u root -p wordpress --auto-repair
更新不同字段爲不同值
UPDATE mytable
SET myfield = CASE id
WHEN 1 THEN 'value'
WHEN 2 THEN 'value'
WHEN 3 THEN 'value'
END
WHERE id IN (1,2,3)
查詢結果導入臨時表
CREATE TEMPORARY TABLE a_test as SELECT id FROM t_log_terminalupgrade GROUP BY machineid,planid HAVING COUNT(1) > 1 ;
批量修改表的引擎
#使用concat函數重組sql語句即可,
#table_name:表名
#table_schema:數據庫名
查看sql:
SELECT CONCAT(table_name,' ', engine)
FROM information_schema.tables WHERE table_schema="testdb" AND ENGINE="MyISAM";
修改sql:
SELECT CONCAT('ALTER TABLE ',table_name,' ENGINE=InnoDB;') FROM information_schema.tables
WHERE table_schema="testdb" AND ENGINE="MyISAM";
查看哪些表被鎖定
show OPEN TABLES where In_use > 0;