1.非聚簇索引一定會回表查詢嗎?
不一定,這涉及到查詢語句所要求的字段是否全部命中了索引,如果全部命中了索引,那么就不必再進行回表查詢。
舉個簡單的例子:假設我們在員工表的年齡上建立了索引,那么當進行的查詢時,在索引的葉子節點上,已經包含了age信息,不會再次進行回表查詢.
select age from employee where age < 20
2.Mysql刪除表幾種方式?有什么區別?
- delete : 僅刪除表數據,支持where條件過濾,支持回滾。記錄日志。因此比較慢。delete from links;
- truncate: 僅刪除所有數據,不支持where條件過濾,不支持回滾。不記錄日志,效率高于delete。truncate table links;
- drop:刪除表數據同時刪除表結構。將表所占的空間都釋放掉。刪除效率最高。drop table links;
3.MySQL自增id不連續問題?
- 唯一鍵沖突 假設執行 SQL 的時候 user 表 id = 10,此時在內存中的自增 id 為11,此時發生唯一鍵沖突寫庫失敗,則 user 表沒有 id = 10 這條記錄,之后 id 從11開始寫入,因此 id 是不連續的。
- 事務回滾 假設同時需要對 user、staff 表進行寫庫操作,執行 SQL 的時候 user 表 id = 10,此時在內存中的自增 id 為11;staff 表 id = 20,此時內存中的自增 id 為21,一旦事務執行失敗,事務回滾,寫庫失敗,則 user 表沒有 id = 10 這條記錄,staff 表沒有 id = 20 這條記錄,user 表從11開始寫入,staff 表從21開始寫入,如此產生 id 不連續的現象。
- 批量寫庫操作 對于批量插入數據的語句,MySQL 有一個批量申請自增 id 的策略: 1. 語句執行過程中,第一次申請自增 id,會分配 1 個;
2. 1 個用完以后,這個語句第二次申請自增 id,會分配 2 個; 3. 2 個用完以后,還是這個語句,第三次申請自增 id,會分配 4 個; 依此類推,同一個語句去申請自增 id,每次申請到的自增 id 個數都是上一次的兩倍。 假設批量往 user 表中寫入四條記錄,則這四條記錄將分為三次申請id, 第一次分配到 id = 1,第二次分配到 id = 2、3 ,第三次分配到 id = 4、5、6、7,當批量寫入四條記錄之后,id = 1、2、3、4將會入庫,但是 id = 5、6、7就被廢棄了,下一個 id 從8開始。
4.選擇合適的存儲引擎?
在選擇存儲引擎時,應根據應用特點選擇合適的存儲引擎,對于復雜的應用系統可以根據實際情況選擇多種存儲引擎進行組合。
下面是常用存儲引擎的適用環境。
- MyISAM:5.1及之前版本默認存儲引擎。如果應用是以讀操作和插入操作為主,=只有很少的更新和刪除操作,并且對事務的完整性、并發性要求不是很高,那么選擇這個存 儲引擎是非常適合的。MyISAM 是在 Web、數據倉儲和其他應用環境下最常使用的存儲引擎 之一。
- InnoDB:5.5及之后默認存儲引擎。用于事務處理應用程序,支持外鍵。如果應用對事務的完整性有比較高的要求,在并發條件下要求數據的一致性,數據操作除了插入和查詢以外,還包括很多的更新、 刪除操作,那么 InnoDB 存儲引擎應該是比較合適的選擇。InnoDB 存儲引擎除了有效地降低 由于刪除和更新導致的鎖定,還可以確保事務的完整提交(Commit)和回滾(Rollback), 對于類似計費系統或者財務系統等對數據準確性要求比較高的系統,InnoDB 都是合適的選 擇。
- MEMORY:將所有數據保存在 RAM 中,在需要快速定位記錄和其他類似數據的環境 下,可提供極快的訪問。MEMORY 的缺陷是對表的大小有限制,太大的表無法 CACHE 在內存中,其次是要確保表的數據可以恢復,數據庫異常終止后表中的數據是可以恢復的。MEMORY 表通常用于更新不太頻繁的小表,用以快速得到訪問結果。
- MERGE:用于將一系列等同的 MyISAM 表以邏輯方式組合在一起,并作為一個對象引用它們。MERGE 表的優點在于可以突破對單個 MyISAM 表大小的限制,并且通過將不同 的表分布在多個磁盤上,可以有效地改善MERGE表的訪問效率。這對于諸如數據倉儲等VLDB 環境十分適合。
5.選擇合適的數據類型?
前提: 使用適合存儲引擎。
選擇原則,根據選定的存儲引擎,確定如何選擇合適的數據類型,下面的選擇方法按存儲引擎分類 :
- MyISAM 數據存儲引擎和數據列
MyISAM數據表,最好使用固定長度的數據列代替可變長度的數據列。
- MEMORY存儲引擎和數據列MEMORY數據表目前都使用固定長度的數據行存儲,因此無論使用CHAR或VARCHAR列都沒有關系。兩者都是作為CHAR類型處理的。
- InnoDB 存儲引擎和數據列建議使用 VARCHAR類型對于InnoDB數據表,內部的行存儲格式沒有區分固定長度和可變長度列(所有數據行 都使用指向數據列值的頭指針) ,因此在本質上,使用固定長度的CHAR列不一定比使 用可變長度VARCHAR列簡單。因而, 主要的性能因 是數據行使用的存儲總量。由于 CHAR 平均占用的空間多于VARCHAR,因此使用VARCHAR來最小化需要處理的數據行的存儲總量和年盤I/O是比較好的。
6.聊聊Mysql字符集!
mysql服務器可以支持多種字符集(可以用show character set命令查看所有mysql支持的字符集),在同一臺服務器、同一個數據庫、甚至同一個表的不同字段都可以指定使用不同的字符集,相比oracle等其他數據庫管理系統,在同一個數據庫只能使用相同的字符集,mysql明顯存在更大的靈活性。
mysql的字符集包括字符集(CHARACTER)和校對規則(COLLATION)兩個概念。字符集是用來定義mysql存儲字符串的方式,校對規則則是定義了比較字符串的方式。字符集和校對規則是一對多的關系, MySQL支持30多種字符集的70多種校對規則。
每個字符集至少對應一個校對規則。可以用SHOW COLLATION LIKE ‘utf8%’;命令查看相關字符集的校對規則
7.如何選擇字符集?
對數據庫來說,字符集更加重要,因為數據庫存儲的數據大部分都是各種文字,字符集對數據庫的存儲,處理性能,以及日后系統的移植,推廣都會有影響。mysql5.6目前支持幾十種字符集,包括ucs2,utf16,utf16le,utf32,utf8和utf8mb4等Unicode字符集。根據應用的需求,考慮以下幾方面的因素。
- 滿足應用支持語言的需求,如果應用要處理各種各樣的文字,或者將發布到使用不同語言的國家或地區,就應該選擇Unicode字符集。對Mysql來說,目前就是utf8,如果要存儲emoji表情需使用utf8mb4。
- 如果應用中涉及已有數據的導入,就要充分考慮數據庫字符集對已有數據的兼容性。假如已有數據是gbk文字,如果選擇gb2312-80為數據庫字符集,就很有可能出現某些文字無法正確導入的問題
- 如果數據庫只支持一般中文,數據量很大,性能要求也很高,那就應該選擇雙字節長編碼的中文字符集,比如gbk。因為,相對于utf8而言,gbk比較“小”,每個漢字只占2個字節,而utf8漢字編碼需要3個字節,這樣可以減少磁盤I/O,數據庫Cache以及網絡傳輸的時間,從而提高性能。相反,如果應用主要處理英文字符,僅有少量漢字數據,那么選擇utf8更好,因為gbk,ucs2,utf16的西文字符編碼都是2個字節,會造成很多不必要的開銷。
- 如果數據庫需要做大量的字符運算,如比較,排序等,那么選擇定長字符集可能更好,因為定長字符集的處理速度要比變長字符集的處理速度快。
- 如果所有客戶端程序都支持相同的字符集,則應該優先選擇該字符集作為數據庫字符集,這樣可以避免因字符集轉換帶來的性能開銷和數據損失。
建議在能夠完全滿足應用的前提下,盡量使用小的字為集。因為更小的字為集意味著能夠節省空間然 減少網絡傳輸字節數,同時由于存儲空間的較小間接的提高了系統的性能。
8.如何查詢最后一行記錄?
select * from links order by id desc limit 1;
9.sql注入問題?
SQL注入攻擊(SQL Injection),簡稱為注入攻擊,SQL注入,被廣泛用于非法獲取網站控制權。這是在應用程序的數據庫層中發生的安全漏洞。在設計程序中,忽略了對輸入字符串中包含的SQL命令的檢查,并且將數據庫誤認為是要運行的常規SQL命令,這導致數據庫受到攻擊,從而可能導致盜竊,修改和刪除數據,并進一步導致網站嵌入惡意代碼,植入后門程序的危害等。
注射位置包括
- 表單提交,主要是POST請求,還有GET請求。
- URL參數提交,主要是GET請求參數。
- Cookie參數的提交。
- HTTP請求標頭中的一些可修改值,例如Referer,User_Agent等。
- 一些邊緣輸入點,例如.mp3文件的某些文件信息。
sql注入的危害
SQL注入的危害不僅體現在數據庫級別,而且還可能危及托管數據庫的操作系統。如果將SQL注入用于掛馬,還可能用來傳播惡意軟件等,這些危害包括但不局限于:
- 數據庫信息泄漏:泄漏用戶存儲在數據庫中的私人信息。作為數據存儲中心,各種類型的私人信息通常存儲在數據庫中。SQL注入攻擊能導致這些隱私信息透明于攻擊者。
- 篡改網頁:通過操作數據庫來篡改特定網頁。
- 網站被掛馬,傳播惡意軟件:修改數據庫一些字段的值,嵌入網馬鏈接,進行掛馬攻擊。
- 數據庫被惡意操作:數據庫服務器受到攻擊,數據庫系統管理員帳戶被篡改。
- 服務器受遠程控制,并安裝了后門。經由數據庫服務器提供的操作系統支持,讓黑客得以修改或控制操作系統。
- 破壞硬盤數據并使整個系統癱瘓。
如何解決SQL注入
解決SQL注入問題的關鍵是嚴格檢查可能來自用戶輸入的所有數據,并使用最小特權原則進行數據庫配置。常用的方案有:
- 所有查詢語句都使用數據庫提供的參數化查詢接口,并且參數化語句使用參數,而不是將用戶輸入變量嵌入SQL語句中。幾乎所有當前的數據庫系統都提供參數化的SQL語句執行接口。使用此接口可以有效地防止SQL注入攻擊。 String sql=”SELECT * FROM user WHERE username=? AND password=?”; //使用?代替參數,預先設置好sql格式,就算在輸入sql關鍵字也不會被sql識別
PreparedStatement pstat=conn.prepareStatement(sql);
pstat.setString(1,username); //設置問號的值
pstat.setString(2,password);
pstat.executeQuery(); - 對進入數據庫的特殊字符(’”<>&*;等)進行轉義處理,或編碼轉換。
- 確認每個數據的類型。例如,數字數據必須是數字,并且數據庫中的存儲字段必須與int類型相對應。
- 應嚴格規定數據長度,以防在一定程度上正確執行較長的SQL注入語句。
- 網站每個數據層的編碼是統一的。建議使用UTF-8編碼。上下層編碼不一致可能會導致某些過濾模型被繞過。
- 嚴格限制網站用戶數據庫的操作權限,并向該用戶提供只能滿足其工作要求的權限,從而最大程度地減少了注入攻擊對數據庫的危害。
- 阻止網站顯示SQL錯誤消息,例如類型錯誤,字段不匹配等,以防止攻擊者使用這些錯誤消息進行判斷。
- 在網站發布之前,建議使用一些專業的SQL注入檢測工具來及時檢測和修補這些SQL注入漏洞。
10.NULL和空串判斷?
MySQL 中的空值包含 NULL 和空字符串。當匹配 NULL 值條件時,使用 IS NULL 和 IS NOT NULL,當匹配空字符串時,使用“=”“<>”“!=”。
本文使用一張名為 t_goods 的數據表,該表用來記錄商品信息,它的記錄如下:
+----+---------------+-----------------+-------------+---------+---------+---------------------+
| id | t_category_id | t_category | t_name | t_price | t_stock | t_upper_time |
+----+---------------+-----------------+-------------+---------+---------+---------------------+
| 1 | 1 | 女裝/女士精品 | T恤 | 39.90 | 1000 | 2020-11-10 00:00:00 |
| 2 | 1 | 女裝/女士精品 | 連衣裙 | 79.90 | 2500 | 2020-11-10 00:00:00 |
| 3 | 1 | 女裝/女士精品 | 衛衣 | 79.90 | 1500 | 2020-11-10 00:00:00 |
| 4 | 1 | 女裝/女士精品 | 牛仔褲 | 89.90 | 3500 | 2020-11-10 00:00:00 |
| 5 | 1 | 女裝/女士精品 | 百褶裙 | 29.90 | 500 | 2020-11-10 00:00:00 |
| 6 | 1 | 女裝/女士精品 | 呢絨外套 | 399.90 | 1200 | 2020-11-10 00:00:00 |
| 7 | 2 | 戶外運動 | 自行車 | 399.90 | 1000 | 2020-11-10 00:00:00 |
| 8 | 2 | 戶外運動 | 山地自行車 | 1399.90 | 2500 | 2020-11-10 00:00:00 |
| 9 | 2 | 戶外運動 | 登山杖 | 59.90 | 1500 | 2020-11-10 00:00:00 |
| 10 | 2 | 戶外運動 | 騎行裝備 | 399.90 | 3500 | 2020-11-10 00:00:00 |
| 11 | 2 | 戶外運動 | 戶外運動外套| 799.90 | 500 | 2020-11-10 00:00:00 |
| 12 | 2 | 戶外運動 | 滑板 | 499.90 | 1200 | 2020-11-10 00:00:00 |
+----+---------------+-----------------+-------------+---------+---------+---------------------+
向 t_goods 數據表中插入兩條名稱為空字符串,上架時間為 NULL 的數據記錄。
mysql> INSERT INTO t_goods
-> (t_category_id, t_category, t_name, t_price, t_stock, t_upper_time)
-> VALUES
-> (1, '女裝/女士精品', '', 399.90, 1200, NULL),
-> (2, '戶外運動', '', 499.90, 1200, NULL);
Query OK, 2 rows affected (0.01 sec)
Records: 2 Duplicates: 0 Warnings: 0
SQL語句執行成功。
匹配 NULL 值
例如,查詢 t_goods 數據表中上架時間為 NULL的 數據。
mysql> SELECT id, t_category, t_name, t_price
-> FROM t_goods
-> WHERE t_upper_time IS NULL;
+----+-----------------+-------------+---------+
| id | t_category | t_name | t_price |
+----+-----------------+-------------+---------+
| 13 | 女裝/女士精品 | | 399.90 |
| 14 | 戶外運動 | | 499.90 |
+----+-----------------+-------------+---------+
2 rows in set (0.00 sec)
IS NOT NULL 與 IS NULL 相反,用于查詢數據表中某個字段的值不是 NULL 的數據記錄。
例如,查詢 t_goods 數據表中上架時間不為 NULL 的數據。
mysql> SELECT id, t_category, t_name, t_price
-> FROM t_goods
-> WHERE t_upper_time IS NOT NULL;
+----+----------------+-------------+---------+
| id | t_category | t_name | t_price |
+----+----------------+-------------+---------+
| 1 | 女裝/女士精品 | T恤 | 39.90 |
| 2 | 女裝/女士精品 | 連衣裙 | 79.90 |
| 3 | 女裝/女士精品 | 衛衣 | 79.90 |
| 4 | 女裝/女士精品 | 牛仔褲 | 89.90 |
| 5 | 女裝/女士精品 | 百褶裙 | 29.90 |
| 6 | 女裝/女士精品 | 呢絨外套 | 399.90 |
| 7 | 戶外運動 | 自行車 | 399.90 |
| 8 | 戶外運動 | 山地自行車 | 1399.90 |
| 9 | 戶外運動 | 登山杖 | 59.90 |
| 10 | 戶外運動 | 騎行裝備 | 399.90 |
| 11 | 戶外運動 | 戶外運動外套 | 799.90 |
| 12 | 戶外運動 | 滑板 | 499.90 |
+----+----------------+-------------+---------+
12 rows in set (0.00 sec)
匹配空字符串
例如,查詢 t_goods 數據表中名稱為空字符串的數據。
mysql> SELECT id, t_category, t_name, t_price
-> FROM t_goods
-> WHERE t_name = '';
+----+-----------------+-------------+---------+
| id | t_category | t_name | t_price |
+----+-----------------+-------------+---------+
| 13 | 女裝/女士精品 | | 399.90 |
| 14 | 戶外運動 | | 499.90 |
+----+-----------------+-------------+---------+
2 rows in set (0.00 sec)
使用“<>”或“!=”運算符能夠查詢數據表中某個字段的值不是空字符串的數據。例如,查詢 t_goods 數據表中名稱不是空字符串的數據。
mysql> SELECT id, t_category, t_name, t_price
-> FROM t_goods
-> WHERE t_name <> '';
+----+----------------+-------------+---------+
| id | t_category | t_name | t_price |
+----+----------------+-------------+---------+
| 1 | 女裝/女士精品 | T恤 | 39.90 |
| 2 | 女裝/女士精品 | 連衣裙 | 79.90 |
| 3 | 女裝/女士精品 | 衛衣 | 79.90 |
| 4 | 女裝/女士精品 | 牛仔褲 | 89.90 |
| 5 | 女裝/女士精品 | 百褶裙 | 29.90 |
| 6 | 女裝/女士精品 | 呢絨外套 | 399.90 |
| 7 | 戶外運動 | 自行車 | 399.90 |
| 8 | 戶外運動 | 山地自行車 | 1399.90 |
| 9 | 戶外運動 | 登山杖 | 59.90 |
| 10 | 戶外運動 | 騎行裝備 | 399.90 |
| 11 | 戶外運動 | 戶外運動外套| 799.90 |
| 12 | 戶外運動 | 滑板 | 499.90 |
+----+----------------+-------------+---------+
12 rows in set (0.00 sec)
11.InnoDB默認事務隔離級別?如何查看事務隔離級別?
- 可重復讀取(REPEATABLE-READ)
- 查看事務隔離級別:
12.什么是回表查詢?
回表就是先通過數據庫索引掃描出數據所在的行,再通過行主鍵id取出索引中未提供的數據,即基于非主鍵索引的查詢需要多掃描一棵索引樹。
因此,可以通過索引先查詢出id字段,再通過主鍵id字段,查詢行中的字段數據,即通過再次查詢提供MySQL查詢速度。
13.如何避免回表?
- 盡量使用主鍵
- 如果必須使用輔助索引,那么盡量避免使用*,直接列出所需列名使用索引覆蓋。如果所需數據僅包含輔助索引列,那么它將不讀取主鍵,因為輔助索引包含輔助索引列的值
14.索引覆蓋是什么?
索引覆蓋是一種避免回表查詢的優化策略。具體的做法就是將要查詢的數據作為索引列建立普通索引(可以是單列索引,也可以一個索引語句定義所有要查詢的列,即聯合索引),這樣的話就可以直接返回索引中的的數據,不需要再通過聚集索引去定位行記錄,避免了回表的情況發生。
覆蓋索引的定義與注意事項
如果一個索引覆蓋(包含)了所有需要查詢的字段的值,這個索引就是覆蓋索引。因為索引中已經包含了要查詢的字段的值,因此查詢的時候直接返回索引中的字段值就可以了,不需要再到表中查詢,避免了對主鍵索引的二次查詢,也就提高了查詢的效率。
要注意的是,不是所有類型的索引都可以成為覆蓋索引的。因為覆蓋索引必須要存儲索引的列值,而哈希索引、空間索引和全文索引等都不存儲索引列值,索引MySQL只能使用B-Tree索引做覆蓋索引。
另外,當發起一個被索引覆蓋的查詢(索引覆蓋查詢)時,在explain(執行計劃)的Extra列可以看到【Using Index】的信息。
覆蓋索引的優點
1.索引條目通常遠小于數據行的大小,因為覆蓋索引只需要讀取索引,極大地減少了數據的訪問量。
2.索引是按照列值順序存儲的,對于IO密集的范圍查找會比隨機從磁盤讀取每一行數據的IO小很多。
3.一些存儲引擎比如MyISAM在內存中只緩存索引,數據則依賴操作系統來緩存,因此要訪問數據的話需要一次系統調用,使用覆蓋索引則避免了這一點。
4.由于InnoDB的聚簇索引,覆蓋索引對InnoDB引擎下的數據庫表特別有用。因為InnoDB的二級索引在葉子節點中保存了行的主鍵值,如果二級索引能夠覆蓋查詢,就避免了對主鍵索引的二次查詢。
15.視圖的優缺點?
優點
1.簡化了操作:此時我們完全不用關心視圖是怎么處理數據的,我們只需要知道如何使用這個結果集即可,視圖相當于一個中間層。
2.更加安全:比如我們可以讓用戶有權去訪問某個視圖,但是不能訪問原表,這樣就可以起到保護原表中某些數據的作用。
3.管理權限是無法細致到某一個列的,通過視圖,則很容易實現。
4.降低耦合:假如我們以后要修改原表的結構,那么我們可以通過修改視圖的定義即可,而不用修改應用程序,對訪問者是不會造成影響的,一般來說,這樣代價會更小。
缺點
1.性能:從數據庫視圖查詢數據可能會很慢,特別是如果視圖是基于其他視圖創建的。
2.表依賴關系:將根據數據庫的基礎表創建一個視圖。每當更改與其相關聯的表的結構時,都必須更改視圖。
16.主鍵和唯一索引區別?
主鍵是一種約束,唯一索引是一種索引,兩者在本質上是不同的。
- 主鍵創建后一定包含一個唯一性索引,唯一性索引并不一定就是主鍵。
- 唯一性索引列允許空值,而主鍵列不允許為空值。
- 主鍵列在創建時,已經默認為非空值 + 唯一索引了。
- 主鍵可以被其他表引用為外鍵,而唯一索引不能。
- 一個表最多只能創建一個主鍵,但可以創建多個唯一索引。
- 主鍵和唯一索引都可以有多列。
- 主鍵更適合那些不容易更改的唯一標識,如自動遞增列、身份證號等。
- 在 RBO 模式下,主鍵的執行計劃優先級要高于唯一索引。兩者可以提高查詢的速度。
索引是一種特殊的文件(InnoDB數據表上的索引是表空間的一個組成部分),它們包含著對數據表里所有記錄的引用指針。
總體來說:主鍵相當于一本書的頁碼,索引相當于書的目錄。
其實主鍵和索引都是鍵,不過主鍵是邏輯鍵,索引是物理鍵,意思就是主鍵不實際存在,而索引實際存在在數據庫中,主鍵一般都要建,主要是用來避免一張表中有相同的記錄,索引一般可以不建,但如果需要對該表進行查詢操作,則最好建,這樣可以加快檢索的速度。
17.如何隨機獲取一條記錄?
select * from posts ORDER BY rand() LIMIT 1;
18.查看當前表有哪些索引?
show index from posts;
19.什么情況下索引不生效?
- 使用不等于查詢
- NULL值
- 列參與了數學運算或者函數。
- 在字符串like時左邊是通配為.比如 %xxx。
- 當mysql分析全表掃描比使用索引快的時候不使用索引。
- 當使用聯合索引,前面一個條件為范圍查詢,后面的即使符合最左前綴原則,也無法使用 引.
20.聊聊MVVC?
本質
多版本并發控制(Multiversion concurrency control, MCC 或 MVCC),是數據庫管理系統常用的一種并發控制,也用于程序設計語言實現事務內存。
樂觀并發控制和悲觀并發控制都是通過延遲或者終止相應的事務來解決事務之間的競爭條件來保證事務的可串行化;這兩種并發控制機制確實能夠從根本上解決并發事務的可串行化的問題,但是其實都是在解決寫沖突的問題,兩者區別在于對寫沖突的樂觀程度不同(悲觀鎖也能解決讀寫沖突問題,但是性能就一般了)。而在實際使用過程中,數據庫讀請求是寫請求的很多倍,我們如果能解決讀寫并發的問題的話,就能更大地提高數據庫的讀性能,而這就是多版本并發控制所能做到的事情。
與悲觀并發控制和樂觀并發控制不同的是,MVCC是為了解決讀寫鎖造成的多個、長時間的讀操作餓死寫操作問題,也就是解決讀寫沖突的問題。MVCC 可以與前兩者中的任意一種機制結合使用,以提高數據庫的讀性能。
數據庫的悲觀鎖基于提升并發性能的考慮,一般都同時實現了多版本并發控制。不僅是MySQL,包括Oracle、PostgreSQL等其他數據庫系統也都實現了MVCC,但各自的實現機制不盡相同,因為MVCC沒有一個統一的實現標準。
總的來說,MVCC的出現就是數據庫不滿用悲觀鎖去解決讀-寫沖突問題,因性能不高而提出的解決方案。
實現方式
MVCC的實現,是通過保存數據在某個時間點的快照來實現的。每個事務讀到的數據項都是一個歷史快照,被稱為快照讀,不同于當前讀的是快照讀讀到的數據可能不是最新的,但是快照隔離能使得在整個事務看到的數據都是它啟動時的數據狀態。而寫操作不覆蓋已有數據項,而是創建一個新的版本,直至所在事務提交時才變為可見。
當前讀和快照讀
什么是MySQL InnoDB下的當前讀和快照讀?
- 當前讀像select lock in share mode(共享鎖), select for update ; update, insert ,delete(排他鎖)這些操作都是一種當前讀,為什么叫當前讀?就是它讀取的是記錄的最新版本,讀取時還要保證其他并發事務不能修改當前記錄,會對讀取的記錄進行加鎖。
- 快照讀像不加鎖的select操作就是快照讀,即不加鎖的非阻塞讀;快照讀的前提是隔離級別不是未提交讀和串行化級別,因為未提交讀總是讀取最新的數據行,而不是符合當前事務版本的數據行。而串行化則會對所有讀取的行都加鎖。
優缺點
MVCC 使大多數讀操作都可以不用加鎖,這樣設計使得讀數據操作很簡單,性能很好,并且也能保證只會讀取到符合標準的行。不足之處是每行記錄都需要額外的存儲空間,需要做更多的行檢查工作,以及一些額外的維護工作。
適用場景
- 解決讀-寫沖突的無鎖并發控制。
- 與上面兩者結合,提升它們的讀性能。
- 可以解決臟讀,幻讀,不可重復讀等事務問題,更新丟失問題除外。
21.sql語句的執行流程!
- client和server建立連接,client發送sql至server(對應連接器這一過程)
- server如果在查詢緩存中發現了該sql,則直接使用查詢緩存的結果返回給client,如果查詢緩存中沒有,則進入下面的步驟(對應查詢緩存這一過程,8.0這一過程已經不存在了,8.0完全拋棄了這個功能)
- server對sql進行語法分析,識別出sql里面的字符串是否符合標準,比如select關鍵字不能寫錯(對應分析器這一過程)
- server對sql進行語義分析,識別出sql里面的字符串的具體意思是什么,比如T1是表名,C1是列名(對應分析器這一過程。3、4步其實解析的過程,這個解析的過程是分析器的工作不是優化器的工作)
- server確定sql的執行路徑,比如走索引還是全表,多表連接時哪張表先走哪張表后走,當你的where條件的可讀性和效率有沖突時mysql內部還會自動進行優化,也就是大家理解的重寫where子句(對應優化器這一過程)
- server對執行sql的用戶進行權限檢查,比如對表是否有權限執行(對應執行器這一過程)
- server執行該sql語句,發送結果給client(對應執行器這一過程)
連接器–>查詢緩存–>分析器–>優化器–>執行器
如果表 T1 中沒有字段 C1,而執行select * from T1 where C1=1會報錯不存在C1這個列,這個過程對應上面第4個過程,對應分析器這一過程
如果用戶對T1表沒有權限,而執行select * from T1 where C1=1會報錯對表T1沒有權限,這個過程對應上面第6個過程,對應執行器這一過程
22.聊聊select 語句執行計劃!
我們都知道用explain xxx分析sql語句的性能,但是具體從explain的結果怎么分析性能以及每個字段的含義你清楚嗎?這里我做下總結記錄,也是供自己以后參考。
首先需要注意:MYSQL 5.6.3以前只能EXPLAIN SELECT; MYSQL5.6.3以后就可以EXPLAIN SELECT,UPDATE,DELETE
explain結果示例:
mysql> explain select * from staff;
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
| 1 | SIMPLE | staff | ALL | NULL | NULL | NULL | NULL | 2 | NULL |
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
1 row in set
先上一個官方文檔表格的中文版:
Column | 含義 |
id | 查詢序號 |
select_type | 查詢類型 |
table | 表名 |
partitions | 匹配的分區 |
type | join類型 |
prossible_keys | 可能會選擇的索引 |
key | 實際選擇的索引 |
key_len | 索引的長度 |
ref | 與索引作比較的列 |
rows | 要檢索的行數(估算值) |
filtered | 查詢條件過濾的行數的百分比 |
Extra | 額外信息 |
這是explain結果的各個字段,分別解釋下含義:
1. id
SQL查詢中的序列號。
id列數字越大越先執行,如果說數字一樣大,那么就從上往下依次執行。
2. select_type
查詢的類型,可以是下表的任何一種類型:
select_type | 類型說明 |
SIMPLE | 簡單SELECT(不使用UNION或子查詢) |
PRIMARY | 最外層的SELECT |
UNION | UNION中第二個或之后的SELECT語句 |
DEPENDENT UNION | UNION中第二個或之后的SELECT語句取決于外面的查詢 |
UNION RESULT | UNION的結果 |
SUBQUERY | 子查詢中的第一個SELECT |
DEPENDENT SUBQUERY | 子查詢中的第一個SELECT, 取決于外面的查詢 |
DERIVED | 衍生表(FROM子句中的子查詢) |
MATERIALIZED | 物化子查詢 |
UNCACHEABLE SUBQUERY | 結果集無法緩存的子查詢,必須重新評估外部查詢的每一行 |
UNCACHEABLE UNION | UNION中第二個或之后的SELECT,屬于無法緩存的子查詢 |
DEPENDENT 意味著使用了關聯子查詢。
3. table
查詢的表名。不一定是實際存在的表名。 可以為如下的值:
- <unionM,N>: 引用id為M和N UNION后的結果。
- <derivedN>: 引用id為N的結果派生出的表。派生表可以是一個結果集,例如派生自FROM中子查詢的結果。
- <subqueryN>: 引用id為N的子查詢結果物化得到的表。即生成一個臨時表保存子查詢的結果。
4. type(重要)
這是最重要的字段之一,顯示查詢使用了何種類型。從最好到最差的連接類型依次為:
system,const,eq_ref,ref,fulltext,ref_or_null,index_merge,unique_subquery,index_subquery,range,index,ALL
除了all之外,其他的type都可以使用到索引,除了index_merge之外,其他的type只可以用到一個索引。
- 1、system
表中只有一行數據或者是空表,這是const類型的一個特例。且只能用于myisam和memory表。如果是Innodb引擎表,type列在這個情況通常都是all或者index
- 2、const
最多只有一行記錄匹配。當聯合主鍵或唯一索引的所有字段跟常量值比較時,join類型為const。其他數據庫也叫做唯一索引掃描
- 3、eq_ref
多表join時,對于來自前面表的每一行,在當前表中只能找到一行。這可能是除了system和const之外最好的類型。當主鍵或唯一非NULL索引的所有字段都被用作join聯接時會使用此類型。
eq_ref可用于使用’=’操作符作比較的索引列。比較的值可以是常量,也可以是使用在此表之前讀取的表的列的表達式。
相對于下面的ref區別就是它使用的唯一索引,即主鍵或唯一索引,而ref使用的是非唯一索引或者普通索引。eq_ref只能找到一行,而ref能找到多行。
- 4、ref
對于來自前面表的每一行,在此表的索引中可以匹配到多行。若聯接只用到索引的最左前綴或索引不是主鍵或唯一索引時,使用ref類型(也就是說,此聯接能夠匹配多行記錄)。
ref可用于使用’=’或'<=>’操作符作比較的索引列。
- 5、 fulltext
使用全文索引的時候是這個類型。要注意,全文索引的優先級很高,若全文索引和普通索引同時存在時,mysql不管代價,優先選擇使用全文索引
- 6、ref_or_null
跟ref類型類似,只是增加了null值的比較。實際用的不多。
eg.
SELECT * FROM ref_table
WHERE key_column=expr OR key_column IS NULL;
- 7、index_merge
表示查詢使用了兩個以上的索引,最后取交集或者并集,常見and ,or的條件使用了不同的索引,官方排序這個在ref_or_null之后,但是實際上由于要讀取多個索引,性能可能大部分時間都不如range
- 8、unique_subquery
用于where中的in形式子查詢,子查詢返回不重復值唯一值,可以完全替換子查詢,效率更高。 該類型替換了下面形式的IN子查詢的ref: value IN (SELECT primary_key FROM single_table WHERE some_expr)
- 9、index_subquery
該聯接類型類似于unique_subquery。適用于非唯一索引,可以返回重復值。
- 10、range
索引范圍查詢,常見于使用 =, <>, >, >=, <, <=, IS NULL, <=>, BETWEEN, IN()或者like等運算符的查詢中。
SELECT * FROM tbl_name
WHERE key_column BETWEEN 10 and 20;
SELECT * FROM tbl_name
WHERE key_column IN (10,20,30);
- 11、index
索引全表掃描,把索引從頭到尾掃一遍。這里包含兩種情況: 一種是查詢使用了覆蓋索引,那么它只需要掃描索引就可以獲得數據,這個效率要比全表掃描要快,因為索引通常比數據表小,而且還能避免二次查詢。在extra中顯示Using index,反之,如果在索引上進行全表掃描,沒有Using index的提示。
# 此表見有一個name列索引。
# 因為查詢的列name上建有索引,所以如果這樣type走的是index
mysql> explain select name from testa;
+----+-------------+-------+-------+---------------+----------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+----------+---------+------+------+-------------+
| 1 | SIMPLE | testa | index | NULL | idx_name | 33 | NULL | 2 | Using index |
+----+-------------+-------+-------+---------------+----------+---------+------+------+-------------+
1 row in set
# 因為查詢的列cusno沒有建索引,或者查詢的列包含沒有索引的列,這樣查詢就會走ALL掃描,如下:
mysql> explain select cusno from testa;
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
| 1 | SIMPLE | testa | ALL | NULL | NULL | NULL | NULL | 2 | NULL |
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
1 row in set
# 包含有未見索引的列
mysql> explain select * from testa;
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
| 1 | SIMPLE | testa | ALL | NULL | NULL | NULL | NULL | 2 | NULL |
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
1 row in set
- 12、all
全表掃描,性能最差。
5. partitions
版本5.7以前,該項是explain partitions顯示的選項,5.7以后成為了默認選項。該列顯示的為分區表命中的分區情況。非分區表該字段為空(null)。
6. possible_keys
查詢可能使用到的索引都會在這里列出來
7. key
查詢真正使用到的索引。 select_type為index_merge時,這里可能出現兩個以上的索引,其他的select_type這里只會出現一個。
8. key_len
查詢用到的索引長度(字節數)。 如果是單列索引,那就整個索引長度算進去,如果是多列索引,那么查詢不一定都能使用到所有的列,用多少算多少。留意下這個列的值,算一下你的多列索引總長度就知道有沒有使用到所有的列了。
key_len只計算where條件用到的索引長度,而排序和分組就算用到了索引,也不會計算到key_len中。
9. ref
如果是使用的常數等值查詢,這里會顯示const,如果是連接查詢,被驅動表的執行計劃這里會顯示驅動表的關聯字段,如果是條件使用了表達式或者函數,或者條件列發生了內部隱式轉換,這里可能顯示為func
10. rows(重要)
rows 也是一個重要的字段。這是mysql估算的需要掃描的行數(不是精確值)。 這個值非常直觀顯示 SQL 的效率好壞, 原則上 rows 越少越好.
11. filtered
這個字段表示存儲引擎返回的數據在server層過濾后,剩下多少滿足查詢的記錄數量的比例,注意是百分比,不是具體記錄數。這個字段不重要
12. extra(重要)
EXplain 中的很多額外的信息會在 Extra 字段顯示, 常見的有以下幾種內容:
- distinct:在select部分使用了distinc關鍵字
- Using filesort:當 Extra 中有 Using filesort 時, 表示 MySQL 需額外的排序操作, 不能通過索引順序達到排序效果. 一般有 Using filesort, 都建議優化去掉, 因為這樣的查詢 CPU 資源消耗大.
# 例如下面的例子:
mysql> EXPLAIN SELECT * FROM order_info ORDER BY product_name G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: order_info
partitions: NULL
type: index
possible_keys: NULL
key: user_product_detail_index
key_len: 253
ref: NULL
rows: 9
filtered: 100.00
Extra: Using index; Using filesort
1 row in set, 1 warning (0.00 sec)
我們的索引是
KEY `user_product_detail_index` (`user_id`, `product_name`, `productor`)
但是上面的查詢中根據 product_name 來排序, 因此不能使用索引進行優化, 進而會產生 Using filesort.
如果我們將排序依據改為 ORDER BY user_id, product_name, 那么就不會出現 Using filesort 了. 例如:
mysql> EXPLAIN SELECT * FROM order_info ORDER BY user_id, product_name G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: order_info
partitions: NULL
type: index
possible_keys: NULL
key: user_product_detail_index
key_len: 253
ref: NULL
rows: 9
filtered: 100.00
Extra: Using index
1 row in set, 1 warning (0.00 sec)
- Using index“覆蓋索引掃描”, 表示查詢在索引樹中就可查找所需數據, 不用掃描表數據文件, 往往說明性能不錯
- Using temporary查詢有使用臨時表, 一般出現于排序, 分組和多表 join 的情況, 查詢效率不高, 建議優化.
23.表最多可創建多少列,多少索引?
前言: 網上關于一張mysql表最多可以創建多少個索引?基本就是兩種答案,一種是不限制,一種是16列, 我認為16的由來應該網上傳著傳著給扭曲, 因為mysql的單個索引最多能包括16列,但是這個是一個索引包含幾列的答案而不是一張可以建多少個索引.真的是誤導人啊!
因為mysql的一些限制跟具體存儲引擎有關,為此以下只列出我們最常用的innoDB和myisam,其他存儲引擎的具體限制可以去官網找.
- innoDB: 最多創建1017列, 最多64個二級索引, 單個索引最多包含16列, 索引最大長度767字節(其實行格式為REDUNDANT,COMPACT最高為767字節,但行格式為DYNAMIC,COMPRESSED最高可達為3072字節), 行大小最大65536字節
- mysiam: 最多4096列, 最多64個二級索引, 單個索引最多包含16列, 索引最大長度1000字節, 行大小最大65536字節
mysql官方文檔地址
- innoDB限制的官方文檔: https://dev.mysql.com/doc/refman/8.0/en/innodb-limits.html
- myisam限制的官方文檔: https://dev.mysql.com/doc/refman/8.0/en/myisam-storage-engine.html
這個問題要根據Mysql具體版本,具體引擎來回答.
24.為什么最好建立一個主鍵?
主鍵是數據庫確保數據行在整張表唯一性的保障,即使業務上本張表沒有主鍵,也建議添加一個自增長的ID列作為主鍵.設定了主鍵之后,在后續的刪改查的時候可能更加快速以及確保操作數據范圍安全.
25.字段為什么要求建議為not null?
MySQL官網這樣介紹:
NULL columns require additional space in the rowto record whether their values are NULL. For MyISAM tables, each NULL columntakes one bit extra, rounded up to the nearest byte.
null值會占用更多的字節,且會在程序中造成很多與預期不符的情況.
- 很多表都包含可為NULL(空值)的列, 即使應用程序并不需要保存NULL 也是如此, 這是因為可為NULL 是列的默認屬性。通常情況下最好指定列為NOT NULL, 除非真的需要存儲NULL 值。
- 如果查詢中包含可為NULL 的列, 對MySQL來說更難優化, 因為可為NULL 的列 使得索引、 索引統計和值比較都更復雜。可為 N ULL的列會使用更多的存儲空間, 在MySQL里也需要特殊處理。當可為NULL的列被索引時, 每個索引記錄需要一個額 外的字節, 在MyISAM 里甚至還可能導致固定大小的索引(例如只有一個整數列的索引)變成可變大小的索引。
- 通常把可為NULL 的列改為NOT NULL 帶來的性能提升比較小, 所以(調優時)沒有 必要首先在現有schema中查找井修改掉這種情況,除非確定這會導致問題。但是, 如果計劃在列上建索引, 就應該盡扯避免設計成可為 NULL 的列。
- 當然也有例外, 例如值得一提的是, lnnoDB 使用單獨的位 (bit) 存儲NULL 值, 所以對于稀疏數據 有很好的空間效率。但這一點不適用千MyISAM。
26.varchar(10)和int(10)代表什么含義
varchar的10代表了申請的空間長度,也是可以存儲的數據的最大長度,而int的10只是代表了展示的長度,不足10位以0填充.也就是說,int(1)和int(10)所能存儲的數字大小以及占用的空間都是相同的,只是在展示時按照長度展示。
27.視圖是什么?對比普通表優勢?
視圖(View)是一種虛擬存在的表,對于使用視圖的用戶來說基本上是透明的。視圖并 不在數據庫中實際存在,行和列數據來自定義視圖的查詢中使用的表,并且是在使用視圖時 動態生成的。
視圖相對于普通的表的優勢主要包括以下幾項。
- 簡單:使用視圖的用戶完全不需要關心后面對應的表的結構、關聯條件和篩選條件, 對用戶來說已經是過濾好的復合條件的結果集。
- 安全:使用視圖的用戶只能訪問他們被允許查詢的結果集,對表的權限管理并不能 限制到某個行某個列,但是通過視圖就可以簡單的實現。
- 數據獨立:一旦視圖的結構確定了,可以屏蔽表結構變化對用戶的影響,源表增加 列對視圖沒有影響;源表修改列名,則可以通過修改視圖來解決,不會造成對訪問 者的影響。
28.coun()在不同引擎的實現方式?
count()的實現方式:在不同的MySQL引擎中,count()實現的方式不同?!?MyISAM引擎中把一個表的總行數直接存在了磁盤上,執行count() 的時候直接返回這個數,效率很高;(不支持事務)· 而InnoDB引擎,執行count()的時候,需要把數據一行一行的從引擎讀出來,然后累計計數;(因為MVCC的實現,應該返回多少行是不確定的(自己能讀到自己事務的未提交記錄,而不能讀到別人事務的未提交記錄))
但是InnoDB在執行count()是做了優化的。InnoDB是索引組織表,主鍵索引樹的葉子節點是數據,而普通索引樹的葉子節點是主鍵值。所以,普通索引樹比主鍵索引樹小很多。對于count()這個操作,遍歷哪個索引樹得到的結果邏輯上是一樣的,所以MySQL優化器會選擇最小的那棵樹來遍歷。在保證邏輯正確的前提下,盡量減少掃描的數據量,是數據庫系統設計的通用法則之一。
- count(* )返回的結果集,一行行的判斷,如果count函數的參數不是NULL,累計值就加1,最后返回累加值。server層要什么,InnoDB就返回什么。(就是SQL語句要什么字段,InnoDB就返回什么字段)
- count(字段) 則表示返回滿足條件的數據行里面,字段值不為NULL的總個數。1.如果字段定義為not null的話,一行行的從記錄里面讀出這個字段,判斷不能為null,按行累加;
2.如果字段定義允許為null,執行的時候判斷到有可能是null,還要把值取出來再判斷一下,不是null才累加。 - count(主鍵id): InnoDB引擎會遍歷整張表,把每一行的id取出來,返回給server層。server層拿到id后,判斷是不可能為空的,就按行累加。
- count(1): InnoDB引擎會遍歷整張表,但不取值。server層對于返回的每一行,放一個數字”1″進去,判斷是不可能為空的,按行累加。
結果: count(*)≈count(1)>count(主鍵id)>count(字段)。
29.MySQL大表優化方案
當MySQL單表記錄數過?時,數據庫的CRUD性能會明顯下降,?些常?的優化措施如下:
限定數據的范圍
務必禁?不帶任何限制數據范圍條件的查詢語句。?如:我們當?戶在查詢訂單歷史的時候,我們可以 控制在?個?的范圍內;
讀寫分離
經典的數據庫拆分?案,主庫負責寫,從庫負責讀;
垂直分區
根據數據庫??數據表的相關性進?拆分。 例如,?戶表中既有?戶的登錄信息?有?戶的基本信息,可以將?戶表拆分成兩個單獨的表,甚?放到單獨的庫做分庫。
簡單來說垂直拆分是指數據表列的拆分,把?張列?較多的表拆分為多張表。 如下圖所示,這樣來說?家應該就更容易理解了。


垂直拆分的優點: 可以使得列數據變?,在查詢時減少讀取的Block數,減少I/O次數。此外, 垂直分區可以簡化表的結構,易于維護。
垂直拆分的缺點: 主鍵會出現冗余,需要管理冗余列,并會引起Join操作,可以通過在應?層進?Join來解決。此外,垂直分區會讓事務變得更加復雜;
?平分區
保持數據表結構不變,通過某種策略存儲數據分?。這樣每??數據分散到不同的表或者庫中,達到了分布式的?的。?平拆分可以?撐?常?的數據量。
?平拆分是指數據表?的拆分,表的?數超過200萬?時,就會變慢,這時可以把?張的表的數據拆成 多張表來存放。舉個例?:我們可以將?戶信息表拆分成多個?戶信息表,這樣就可以避免單?表數據 量過?對性能造成影響。


?平拆分可以?持?常?的數據量。需要注意的?點是:分表僅僅是解決了單?表數據過?的問題,但 由于表的數據還是在同?臺機器上,其實對于提升MySQL并發能?沒有什么意義,所以 ?平拆分最好分庫 。
?平拆分能夠 ?持?常?的數據量存儲,應?端改造也少,但 分?事務難以解決 ,跨節點Join性能較差,邏輯復雜?!禞ava?程師修煉之道》的作者推薦 **盡量不要對數據進?分?,因為拆分會帶來邏輯、部署、運維的各種復雜度 ,?般的數據表在優化得當的情況下?撐千萬以下的數據量是沒有太?問題的。如果實在要分?,盡量選擇客戶端分?架構,這樣可以減少?次和中間件的?絡I/O。
下?補充?下數據庫分?的兩種常??案:
- 客戶端代理: 分?邏輯在應?端,封裝在jar包中,通過修改或者封裝JDBC層來實現。當當?的Sharding-JDBC、阿?的TDDL是兩種?較常?的實現。
- 中間件代理:應?和數據中間加了?個代理層。分?邏輯統?維護在中間件服務中。我們現在談的 Mycat 、360的Atlas、?易的DDB等等都是這種架構的實現。
30.解釋?下什么是池化設計思想.什么是數據庫連接池?為什么需要數據庫連接池?
池化設計應該不是?個新名詞。我們常?的如java線程池、jdbc連接池、redis連接池等就是這類設計 的代表實現。這種設計會初始預設資源,解決的問題就是抵消每次獲取資源的消耗,如創建線程的開銷,獲取遠程連接的開銷等。就好?你去?堂打飯,打飯的?媽會先把飯盛好?份放那?,你來了就直 接拿著飯盒加菜即可,不?再臨時?盛飯?打菜,效率就?了。除了初始化資源,池化設計還包括如下 這些特征:池?的初始值、池?的活躍值、池?的最?值等,這些特征可以直接映射到java線程池和數據庫連接池的成員屬性中。
數據庫連接本質就是?個 socket 的連接。數據庫服務端還要維護?些緩存和?戶權限信息之類的 所以占?了?些內存。我們可以把數據庫連接池是看做是維護的數據庫連接的緩存,以便將來需要對數據 庫的請求時可以重?這些連接。為每個?戶打開和維護數據庫連接,尤其是對動態數據庫驅動的?站應
?程序的請求,既昂貴?浪費資源。在連接池中,創建連接后,將其放置在池中,并再次使?它,因此 不必建?新的連接。如果使?了所有連接,則會建??個新連接并將其添加到池中。 連接池還減少了?戶必須等待建?與數據庫的連接的時間。
31.分庫分表之后,id 主鍵如何處理?
因為要是分成多個表之后,每個表都是從 1 開始累加,這樣是不對的,我們需要?個全局唯?的 id來?持。
?成全局 id 有下?這?種?式:
UUID:不適合作為主鍵,因為太?了,并且?序不可讀,查詢效率低。?較適合?于?成唯?的 名字的標示?如?件的名字。
數據庫?增 id : 兩臺數據庫分別設置不同步?,?成不重復ID的策略來實現?可?。這種?式?成的 id 有序,但是需要獨?部署數據庫實例,成本?,還會有性能瓶頸。
利? redis ?成 id : 性能?較好,靈活?便,不依賴于數據庫。但是,引?了新的組件造成系統更加復雜,可?性降低,編碼更加復雜,增加了系統成本。
Twitter**的snowflake算法** :Github 地址:
https://github.com/twitter-archive/snowflake。
美團的Leaf分布式**ID?成系統** :Leaf 是美團開源的分布式ID?成器,能保證全局唯?性、趨勢遞增、單調遞增、信息安全,??也提到了?種分布式?案的對?,但也需要依賴關系數據庫、Zookeeper等中間件。感覺還不錯。美團技術團隊的?篇?章:
https://tech.meituan.com/2017/04/21/mt-leaf.html 。
32.?條SQL語句執?得很慢的原因有哪些?
- 大多數情況下很正常,偶爾很慢,則有如下原因(1)、數據庫在刷新臟頁,例如 redo log 寫滿了需要同步到磁盤。(2)、執行的時候,遇到鎖,如表鎖、行鎖。
- 這條 SQL 語句一直執行的很慢,則有如下原因。(1)、沒有用上索引:例如該字段沒有索引;由于對字段進行運算、函數操作導致無法用索引。(2)、數據庫選錯了索引。
33.聊聊存儲過程
一組為了完成特定功能的 SQL 語句集,存儲在數據庫中,經過第一次編譯后再次調用不需要再次編譯,用戶通過指定存儲過程的名字并給出參數(如果該存儲過程帶有參數)來執行它。存儲過 程是數據庫中的一個重要對象。
存儲過程優化思路:
- 盡量利用一些sql 語句來替代一些小循環,例如聚合函數,求平均函數等。
- 中間結果存放于臨時表,加索引。
- 少使用游標。sql 是個集合語言,對于集合運算具有較高性能。而 cursors 是過程運算。比如對一個 100 萬行的數據進行查詢。游標需要讀表 100 萬次,而不使用游標則只需要少量幾次讀取。
- 事務越短越好。sqlserver 支持并發操作。如果事務過多過長,或者隔離級別過高,都會造成并發操作的阻塞,死鎖。導致查詢極慢,cpu 占用率極地。
- 使用try-catch 處理錯誤異常。
- 查找語句盡量不要放在循環內。
34.mysql里記錄貨幣用什么字段類型好?
NUMERIC和DECIMAL類型被Mysql實現為同樣的類型,這在SQL92標準允許。他們被用于保存值,該值的準確精度是極其重要的值,例如與金錢有關的數據。
當聲明一個類是這些類型之一時,精度和規模的能被(并且通常是)指定。例如:salary DECIMAL(9,2)在這個例子中,9(precision)代表將被用于存儲值的總的小數位數,而2(scale)代表將被用于存儲小數點后的位數。因此,在這種情況下,能被存儲在salary列中的值的范圍是從-9999999.99到9999999.99。在ANSI/ISO SQL92中,句法DECIMAL(p)等價于DECIMAL(p,0)。同樣,句法DECIMAL等價于DECIMAL(p,0),這里實現被允許決定值p。
Mysql當前不支持DECIMAL/NUMERIC數據類型的這些變種形式的任一種。這一般說來不是一個嚴重的問題,因為這些類型的主要益處得自于明顯地控制精度和規模的能力。DECIMAL和NUMERIC值作為字符串存儲,而不是作為二進制浮點數,以便保存那些值的小數精度。一個字符用于值的每一位、小數點(如果scale>0)和“-”符號(對于負值)。如果scale是0,DECIMAL和NUMERIC值不包含小數點或小數部分。DECIMAL和NUMERIC值得最大的范圍與DOUBLE一樣,但是對于一個給定的DECIMAL或NUMERIC列,實際的范圍可由制由給定列的precision或scale限制。當這樣的列賦給了小數點后面的位超過指定scale所允許的位的值,該值根據scale四舍五入。
當一個DECIMAL或NUMERIC列被賦給了其大小超過指定(或缺省的)precision和scale隱含的范圍的值,Mysql存儲表示那個范圍的相應的端點值。
35.CHAR 和VARCHAR 的區別?
- 區別一,定長和變長char 表示定長,長度固定,varchar表示變長,即長度可變。char如果插入的長度小于定義長度時,則用空格填充;varchar小于定義長度時,還是按實際長度存儲,插入多長就存多長。因為其長度固定,char的存取速度還是要比varchar要快得多,方便程序的存儲與查找;但是char也為此付出的是空間的代價,因為其長度固定,所以會占據多余的空間,可謂是以空間換取時間效率。varchar則剛好相反,以時間換空間。
- 區別之二,存儲的容量不同對 char 來說,最多能存放的字符個數 255,和編碼無關。而 varchar 呢,最多能存放 65532 個字符。varchar的最大有效長度由最大行大小和使用的字符集確定。整體最大長度是 65,532字節。
36.HAVNG 子句 和 WHERE的異同點?
一、相同點:
二者的相同點是在功能上來說的,HAVING子句和WHERE子句都可以用來設定限制條件以使查詢結果滿足一定的條件限制。
二、區別如下:
- WHERE是先分組再篩選記錄,WHERE在聚合前先篩選記錄.也就是說作用在GROUP BY 子句和HAVING子句前;而 HAVING子句在聚合后對組記錄進行篩選。
- 在 SQL 中增加 HAVING 子句原因是,WHERE 關鍵字無法與合計函數一起使用。而HAVING子句中可以。HAVING 子句是聚組函數唯一出現的地方。
- 在查詢過程中聚合語句(SUM,MIN,MAX,AVG,COUNT)要比HAVING子句優先執行。而WHERE子句在查詢過程中執行優先級高于聚合語句。
- HAVING 子句中的每一個元素必須出現在SELECT列表中。
37.drop,delete與truncate的區別?
drop直接刪掉表 truncate刪除表中數據,再插入時自增長id又從1開始 delete刪除表中數據,可以加where字句。
- delete語句執行刪除的過程是每次從表中刪除一行,并且同時將該行的刪除操作作為事務記錄在日志中保存以便進行進行回滾操作。truncate TABLE 則一次性地從表中刪除所有的數據并不把單獨的刪除操作記錄記入日志保存,刪除行是不能恢復的。并且在刪除的過程中不會激活與表有關的刪除觸發器。執行速度快。
- 表和索引所占空間。當表被truncate后,這個表和索引所占用的空間會恢復到初始大小,而delete操作不會減少表或索引所占用的空間。drop語句將表所占用的空間全釋放掉。
- 應用范圍。truncate只能對TABLE;delete可以是table和view
- truncate和delete只刪除數據,而drop則刪除整個表(結構和數據)。
- truncate與不帶where的delete :只刪除數據,而不刪除表的結構(定義)drop語句將刪除表的結構被依賴的約束(constrain),觸發器(trigger)索引(index);依賴于該表的存儲過程/函數將被保留,但其狀態會變為:invalid。
- delete語句為DML(data maintain Language),這個操作會被放到 rollback segment中,事務提交后才生效。如果有相應的 trigger,執行的時候將被觸發。truncate、drop是DLL(data define language),操作立即生效,原數據不放到 rollback segment中,不能回滾
- 在沒有備份情況下,謹慎使用 drop 與 truncate。要刪除部分數據行采用delete且注意結合where來約束影響范圍?;貪L段要足夠大。要刪除表用drop;若想保留表而將表中數據刪除,如果于事務無關,用truncate即可實現。如果和事務有關,或老師想觸發trigger,還是用delete。
- truncate table 表名 速度快,而且效率高,因為: truncate table 在功能上與不帶 WHERE 子句的 delete語句相同:二者均刪除表中的全部行。但 truncate TABLE 比 delete速度快,且使用的系統和事務日志資源少。delete語句每次刪除一行,并在事務日志中為所刪除的每行記錄一項。truncate TABLE
- 通過釋放存儲表數據所用的數據頁來刪除數據,并且只在事務日志中記錄頁的釋放。
- truncate TABLE 刪除表中的所有行,但表結構及其列、約束、索引等保持不變。新行標識所用的計數值重置為該列的種子。如果想保留標識計數值,請改用 delete。如果要刪除表定義及其數據,請使用 drop TABLE 語句。
- 對于由 FOREIGN KEY 約束引用的表,不能使用 truncate TABLE,而應使用不帶 WHERE 子句的 delete語句。由于 truncate TABLE 不記錄在日志中,所以它不能激活觸發器。
38.MyISAM和InnoDB區別
MyISAM是MySQL的默認數據庫引擎(5.5版之前)。雖然性能極佳,?且提供了?量的特性,包括全?索引、壓縮、空間函數等,但MyISAM不?持事務和?級鎖,?且最?的缺陷就是崩潰后?法安全恢復。不過,5.5版本之后,MySQL引?了InnoDB(事務性數據庫引擎),MySQL 5.5版本后默認的存儲引擎為InnoDB。?多數時候我們使?的都是 InnoDB 存儲引擎,但是在某些情況下使? MyISAM 也是合適的?如讀密集的情況下。(如果你不介意 MyISAM 崩潰恢復問題的話)。
兩者的對?
是否?持?級鎖
- MyISAM 只有表級鎖(table-level locking),?InnoDB ?持?級鎖(rowlevel locking)和表級鎖,默認為?級鎖。
是否?持事務和崩潰后的安全恢復
- MyISAM 強調的是性能,每次查詢具有原?性,其執?速度?InnoDB類型更快,但是不提供事務?持。但是InnoDB 提供事務?持事務,外部鍵等?級數據庫功能。具有事務(commit)、回滾(rollback)和崩潰修復能?(crash recovery capabilities)的事務安全(transaction-safe (ACID compliant))型表。
是否?持外鍵
- MyISAM不?持,?InnoDB?持。
是否?持MVCC
- 僅 InnoDB ?持。應對?并發事務, MVCC?單純的加鎖更?效;MVCC只在READ COMMITTED 和 REPEATABLE READ 兩個隔離級別下?作;MVCC可以使? 樂觀(optimistic)鎖 和 悲觀(pessimistic)鎖來實現;各數據庫中MVCC實現并不統?。
一般情況下我們選擇 InnoDB 都是沒有問題的,但是某些情況下你并不在乎可擴展能?和并發能?,也不需要事務?持,也不在乎崩潰后的安全恢復問題的話,選擇MyISAM也是?個不錯的選擇。但是?般情況下,我們都是需要考慮到這些問題的。
不要輕易相信“MyISAM?InnoDB快”之類的經驗之談,這個結論往往不是絕對的。在很多我們已知場景中,InnoDB的速度都可以讓MyISAM望塵莫及,尤其是?到了聚簇索引,或者需要訪問的數據都可以放?內存的應?。
39.數據庫三范式是什么?
第一范式(1NF)
- 數據表中的每一列(字段),必須是不可拆分的最小單元,也就是確保每一列的原子性。所有關系型數據庫系統都滿足第一范式數據庫表中的字段都是單一屬性的,不可再分。
- 兩列的屬性相近或相似或一樣,盡量合并屬性一樣的列,確保不產生冗余數據。
第二范式(2NF)
- 是在第一范式(1NF)的基礎上建立起來的,即滿足第二范式(2NF)必須先滿足第一范式(1NF)。
- 要求數據庫表中的每行必須可以被惟一地區分,即一行數據只做一件事。只要數據列中出現數據重復,就要把表拆分開來。
- 通常需要為表加上一個列,以存儲各個實例的惟一標識。這個惟一屬性列被稱為主關鍵字或主鍵。
第三范式(3N)
- 滿足第三范式(3NF)必須先滿足第二范式(2NF)。
- 要求一個數據庫表中不包含已在其它表中已包含的非主關鍵字信息,即數據不能存在傳遞關系,。像:a–>b–>c 列之間含有這樣的關系,是不符合第三范式的。
- 特征:每一列只有一個值 ,每一行都能區分,每一個表都不包含其他表已經包含的非主關鍵字信息。
設計思考
- 三大范式只是一般設計數據庫的基本理念,可以建立冗余較小、結構合理的數據庫。如果有特殊情況,當然要特殊對待,數據庫設計最重要的是看需求跟性能,需求>性能>表結構。所以不能一味的去追求范式建立數據庫表。
40.hash索引和b+tree索引底層是怎么實現的(實現原理),有什么不一樣?
hash索引
實現
- 把索引的值做hash運算,并存放到hash表中,進行查找時,調用一次hash函數就可以獲取到相應的鍵值,之后進行回表查詢獲得實際數據。使用較少,一般是memory引擎使用。。
hash索引的優點
- 因為使用hash表存儲,按照常理,hash的性能比b+tree效率高很多。
hash索引的缺點。
- hash索引只能適用于精確的值比較,=,in,或者<>;無法使用范圍查詢。
- 無法使用索引排序;
- 組合hash索引無法使用部分索引;
- 如果大量索引hash值相同,性能較低;
b+tree索引
實現
- 底層是多路平衡查找樹。對于每一次的查詢都是從根節點出發,查找到葉子節點方可獲的所查鍵值,然后根據查詢判斷是否需要回表查詢數據。innodb使用b+tree索引。
- innodb中,存在兩種索引類型
- 主鍵索引(primary key),在索引內容中直接保存數據的地址。
- 其他索引,在索引內容中保存的是指向主鍵索引的引用。
所以在使用innodb的時候,要盡量的使用主鍵索引,速度非??臁?/p>
b+tree索引優點
- b+tree所有的節點都遵循(左節點小于父節點,右節點大于父節點,多叉樹也類似)天然支持范圍查詢。查詢效率比較穩定,對于所有的查詢都是從根節點到葉子節點,且樹的高度較低。
hash索引與b+tree索引不同
- hash索引進行等值查詢更快(一般情況),但是無法進行范圍查詢。
- hash索引不支持使用索引排序。
- hash索引不支持模糊查詢以及多列索引的最左前綴匹配,原因是hash函數的不可預測。
- hash索引任何時候都避免不了回表查詢數據,而b+tree在符合某些條件(聚集索引、覆蓋索引)的時候可以只通過索引完成查詢。
- hash索引雖然在等值查詢上較快,但是不穩定,性能不可預測,當某個鍵值存在大量重復的時候,發生hash碰撞,此時效率可能極差。而b+tree查詢效率比較穩定,對于所有的查詢都是從根節點到葉子節點,且樹的高度較低。
因此,在大多數情況下,直接選擇b+tree樹索引可以獲得穩定且較好的查詢速度,而不需要使用hash索引。
41.MYSQL有哪些索引?
數據結構角度
B+TREE
- 是B-Tree的改進版本,同時也是數據庫索引所采用的存儲結構。數據都在葉子節點上,并且增加了順序訪問指針,每個葉子節點都指向相鄰的葉子節點的地址。相比B-Tree來說,進行范圍查找時只需要查找兩個節點,進行遍歷即可。而B-Tree需要獲取所有節點,相比之下B+Tree效率更高
HASH
- 基于哈希表實現,只有精確匹配索引所有列的查詢才有效。
FULLTEXT
- 一種特殊類型的索引,它查找的是文本中的關鍵詞,而不是直接比較索引中的值,全文索引更類似于搜索引擎做的事情,實際生產中我們一般不會使用MySQL來做類似搜索引擎的工作。
R-TREE
- myisam支持空間索引,可以用作地理數據存儲,R-tree無須前綴索引??臻g索引會從所有維度來索引數據。查詢時,可以有效地使用任意維度來組合查詢。
物理存儲角度
聚集索引(clustered index)
- 指索引項的排序方式和表中數據記錄排序方式一致的索引。
- 也就是說聚集索引的順序就是數據的物理存儲順序。它會根據聚集索引鍵的順序來存儲表中的數據,即對表的數據按索引鍵的順序進行排序,然后重新存儲到磁盤上。因為數據在物理存放時只能有一種排列方式,所以一個表只能有一個聚集索引。
- 聚集索引的使用場合為: a.查詢命令的回傳結果是以該字段為排序依據的; b.查詢的結果返回一個區間的值; c.查詢的結果返回某值相同的大量結果集。
- 聚集索引會降低 insert,和update操作的性能,所以,是否使用聚集索引要全面衡量。
非聚集索引(non-clusterd index)
- 索引順序與物理存儲順序不同。
- 非聚集索引的使用場合為: a.查詢所獲數據量較少時; b.某字段中的數據的唯一性比較高時;
邏輯角度
- 普通索引:僅加速查詢。
- 唯一索引:加速查詢+列值唯一(可以有null)。
- 主鍵索引:加速查詢+列值唯一(不可以有null)+表中只有一個。
- 組合索引:多列值組成一個索引,專門擁有組合搜索,其效率大于索引合并。
- 全文索引:對文本的內容進行分詞,進行搜索。
42.說說索引有哪些設計原則?
什么是索引
在關系數據庫中,索引是一種單獨的、物理的對數據庫表中一列或多列的值進行排序的一種存儲結構,它是某個表中一列或者若干列值的集合和相應的指向表中物理標識這些值的數據頁的邏輯指針清單。索引的作用相當于圖書的目錄,可以根據目錄中的頁碼快速找到所需的內容。
索引設計原則
- 搜索的索引列,不一定是所要選擇的列。最適合索引的列是在出現在WHERE子句、連接子句、排序 order by 、聚合group by 指定的列,而不是出現在SELECT關鍵字后的選擇列表中的列。
- 使用唯一索引??紤]某列中值的分布。對唯一值的列,索引的效果最好,而具有多個重復值的列,其索引效果最差。
- 使用短索引。如果對字符串列進行索引,應該指定一個前綴長度,只要有可能就應該這樣做。例如:有一個CHAR(200)列,如果在前10個或者20個字符內,多數值是惟一的,那么就不要對整個列進行索引。
- 利用最左前綴。在創建一個n列的索引時,實際是創建了MySQL可利用的n個索引。多列索引可起幾個索引的作用,因為可利用索引中最左邊的列集來匹配行。這樣的列集稱為最左前綴。(這與索引一個列的前綴不同,索引一個列的前綴是利用該列的前你個字符作為索引值)
- 不要過度索引,刪除不再使用或者很少使用的索引。每個額外的索引都要占額外的磁盤空間,并降低寫操作的性能。在修改表的內容時,索引必須進行更新,有時可能進行重構,因此,索引越多,所花的時間越長。如果有一個索引很少利用或者從不使用,那么會不必要地減緩表的修改速度。此外,MySQL在生產一個執行計劃時,要考慮各個索引,這也要費時間。創建多余的索引給查詢優化帶來了更多的工作。索引太多,也可能會使MYSQL選擇不到所要使用的最好索引。只保持所需要的索引有利于查詢優化。如果想給已有索引的表增加索引,應該考慮所要增加的索引是否是現有多列索引的最左索引。
- 考慮在列上進行的比較類型。索引可用于”<“、”<=”、”=”、”>=”、”>”和BETWEEN運算。在模式具有一個直接量前綴時,索引也用于LIKE運算。
- 使用數據量少的索引,如果索引的值很長,那么查詢的速度會受到影響。
- 選擇區分度高的列作為索引,區分度的公式是表示字段不重復的比例。
- 索引列不能參與計算,保持列“干凈”:帶函數的查詢不參與索引。
- 更新非常頻繁的字段不適合創建索引;原因,索引有維護成本。
43.MYSQL并發事務帶來哪些問題?
在典型的應?程序中,多個事務并發運?,經常會操作相同的數據來完成各?的任務(多個?戶對同?數據進?操作)。并發雖然是必須的,但可能會導致以下的問題。
臟讀(Dirty read)
- 當?個事務正在訪問數據并且對數據進?了修改,?這種修改還沒有提交到數據庫中,這時另外?個事務也訪問了這個數據,然后使?了這個數據。因為這個數據是還沒有提交的數據,那么另外?個事務讀到的這個數據是“臟數據”,依據“臟數據”所做的操作可能是不正確的。
丟失修改(Lost to modify)
- 指在?個事務讀取?個數據時,另外?個事務也訪問了該數據,那么在第?個事務中修改了這個數據后,第?個事務也修改了這個數據。這樣第?個事務內的修改結果就被丟失,因此稱為丟失修改。例如:事務1讀取某表中的數據A=20,事務2也讀取A=20,事務1修改A=A-1,事務2也修改A=A-1,最終結果A=19,事務1的修改被丟失。
不可重復讀(Unrepeatableread)
- 指在?個事務內多次讀同?數據。在這個事務還沒有結束時,另?個事務也訪問該數據。那么,在第?個事務中的兩次讀數據之間,由于第?個事務的修改導致第?個事務兩次讀取的數據可能不太?樣。這就發?了在?個事務內兩次讀到的數據是不?樣的情況,因此稱為不可重復讀。
幻讀(Phantom read)
- 幻讀與不可重復讀類似。它發?在?個事務(T1)讀取了??數據,接著另?個并發事務(T2)插?了?些數據時。在隨后的查詢中,第?個事務(T1)就會發現多了?些原本不存在的記錄,就好像發?了幻覺?樣,所以稱為幻讀。
不可重復讀和幻讀區別
- 不可重復讀的重點是修改?如多次讀取?條記錄發現其中某些列的值被修改,幻讀的重點在于新增或者刪除?如多次讀取?條記錄發現記錄增多或減少了。
44.數據庫事務的四大特性(ACID)
事務(TRANSACTION)是作為單個邏輯工作單元執行的一系列操作,這些操作作為一個整體一起向系統提交,要么都執行、要么都不執行 。事務是一個不可分割的工作邏輯單元 事務必須具備以下四個屬性,簡稱ACID 屬性:


原子性(Atomicity)
- 事務是一個完整的操作。事務的各步操作是不可分的(原子的);要么都執行,要么都不執行。
一致性(Consistency)
- 事務執行的結果必須是使數據庫從一個一致性狀態變到另一個一致性狀態。因此當數據庫只包含成功事務提交的結果時,就說數據庫處于一致性狀態。如果數據庫系統 運行中發生故障,有些事務尚未完成就被迫中斷,這些未完成事務對數據庫所做的修改有一部分已寫入物理數據庫,這時數據庫就處于一種不正確的狀態,或者說是 不一致的狀態。
隔離性(Isolation)
- 事物的隔離性,基于原子性和一致性,因為事物是原子化,量子化的,所以,事物可以有多個原子包的形式并發執行,但是,每個事物互不干擾。-多個用戶并發訪問操作數據庫時,一個用戶的事務操作不能被其它的用戶事務所干擾,也就是多個并發事務之間操作是隔離的。
持久性(Durability)
- 是指一個事務一旦提交成功,那么對數據庫的數據的修改是永久性的。就算數據庫出現故障或關機,數據也是永久保存下來的。
45.InnoDB支持些事務隔離級別,他們有什么區別?
Read Uncommitted(讀取未提交內容)
- 在該隔離級別,所有事務都可以看到其他未提交事務的執行結果。本隔離級別很少用于實際應用,因為它的性能也不比其他級別好多少。讀取未提交的數據,也被稱之為臟讀(Dirty Read)。
Read Committed(讀取提交內容)
- 這是大多數數據庫系統的默認隔離級別(但不是MySQL默認的)。它滿足了隔離的簡單定義:一個事務只能看見已經提交事務所做的改變。這種隔離級別也支持所謂的不可重復讀(Nonrepeatable Read),因為同一事務的其他實例在該實例處理其間可能會有新的commit,所以同一select可能返回不同結果。
Repeatable Read(可重讀)
- 這是MySQL的默認事務隔離級別,它確保同一事務的多個實例在并發讀取數據時,會看到同樣的數據行。不過理論上,這會導致另一個棘手的問題:幻讀(Phantom Read)。簡單的說,幻讀指當用戶讀取某一范圍的數據行時,另一個事務又在該范圍內插入了新行,當用戶再讀取該范圍的數據行時,會發現有新的“幻影” 行。InnoDB和Falcon存儲引擎通過多版本并發控制(MVCC,Multiversion Concurrency Control 間隙鎖)機制解決了該問題。注:其實多版本只是解決不可重復讀問題,而加上間隙鎖(也就是它這里所謂的并發控制)才解決了幻讀問題
Serializable(可串行化)
- 這是最高的隔離級別,它通過強制事務排序,使之不可能相互沖突,從而解決幻讀問題。簡言之,它是在每個讀的數據行上加上共享鎖。在這個級別,可能導致大量的超時現象和鎖競爭。
匯總


版權聲明:本文內容由互聯網用戶自發貢獻,該文觀點僅代表作者本人。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如發現本站有涉嫌抄襲侵權/違法違規的內容, 請發送郵件至 舉報,一經查實,本站將立刻刪除。