目錄
Myibatis
myibatis執行過程
mybatis的優缺點有哪些?
mybatis和hibernate有什么區別?
mybatis中#{}和${}的區別是什么?
簡述一下mybatis插件運行原理及開發流程?(插件四大天王)
mybatis的mapper沒有實現類
MyBatis 與 Spring 框架整合
MyBatis 緩存
Mybatis是如何進行分頁的?分頁插件的原理是什么?
MyBatis編程步驟是什么樣的?
Mybatis都有哪些Executor執行器?它們之間的區別是什么?
模糊查詢like語句該怎么寫
在mapper中如何傳遞多個參數
在 MyBatis 中進行一對一和一對多的關聯查詢
Select * 的缺點
1. 不需要的列會增加數據傳輸時間和網絡開銷
2. 對于無用的大字段,如 varchar、blob、text,會增加 io 操作
3. 失去MySQL優化器“覆蓋索引”策略優化的可能性
select count(*)和select count(1)的區別
左連接 left Join 右連接,內連接
數據庫的五大范式
MySql的三種日志及作用
redo log和binlog區別
索引的基本原理
B+ 樹索引結構
索引的最左匹配原則
mysql聚簇和非聚簇索引的區別是什么?
mysql索引結構有哪些,各自的優劣是什么?
索引的設計原則有哪些?
索引失效的十大原因
什么是回表查詢?
什么是覆蓋索引?***
索引下推
mysql鎖的類型有哪些?
mysql執行計劃怎么看?
事務的基本特性是什么?
MySQL的隔離級別有哪些?
怎么處理MySQL的慢查詢?
ACID是靠什么保證的?
什么是MVCC?
MVCC解決的問題是什么?
MVCC實現原理是什么?
RC(讀提交內容)、RR(可重復讀)級別下的InnoDB快照讀有什么不同
什么是mysql的主從復制?
mysql為什么需要主從同步?
mysql復制原理是什么?
簡述Myisam和Innodb的區別?
簡述mysql中索引類型有哪些,以及對數據庫的性能的影響?
mysql聚簇和非聚簇索引的區別
Myibatis
myibatis執行過程
1讀取MyBatis的配置文件。
mybatis-config.xml為MyBatis的全局配置文件,用于配置數據庫連接信息。
2加載映射文件。映射文件即SQL映射文件,該文件中配置了操作數據庫的SQL語句,需要在MyBatis配置文件mybatis-config.xml中加載。mybatis-config.xml 文件可以加載多個映射文件,每個文件對應數據庫中的一張表。
3構造會話工廠。
通過MyBatis的環境配置信息構建會話工廠SqlSessionFactory。
4 創建會話對象。
由會話工廠創建SqlSession對象,該對象中包含了執行SQL語句的所有方法。
5 Executor執行器。
MyBatis底層定義了一個Executor接口來操作數據庫,它將根據SqlSession傳遞的參數動態地生成需要執行的SQL語句,同時負責查詢緩存的維護。
6MappedStatement對象。
在Executor接口的執行方法中有一個MappedStatement類型的參數,該參數是對映射信息的封裝,用于存儲要映射的SQL語句的id、參數等信息。
7 輸入參數映射。
輸入參數類型可以是Map、List等集合類型,也可以是基本數據類型和POJO類型。輸入參數映射過程類似于JDBC對preparedStatement對象設置參數的過程。
8 輸出結果映射。
輸出結果類型可以是Map、List等集合類型,也可以是基本數據類型和POJO類型。輸出結果映射過程類似于JDBC對結果集的解析過程。
mybatis的優缺點有哪些?
1、Mybait的優點:
(1)簡單易學,容易上手(相比于Hibernate) 基于SQL編程; (2)JDBC相比,減少了50%以上的代碼量,消除了JDBC大量冗余的代碼,不需要手動開關連接; (3)很好的與各種數據庫兼容(因為MyBatis使用JDBC來連接數據庫,所以只要JDBC支持的數據庫MyBatis都支持,而JDBC提供了可擴展性,所以只要這個數據庫有針對Java的jar包就可以就可以與MyBatis兼容),開發人員不需要考慮數據庫的差異性。 (4)提供了很多第三方插件(分頁插件 / 逆向工程); (5)能夠與Spring很好的集成; (6)MyBatis相當靈活,不會對應用程序或者數據庫的現有設計強加任何影響,SQL寫在XML里,從程序代碼中徹底分離,解除sql與程序代碼的耦合,便于統一管理和優化,并可重用。 (7)提供XML標簽,支持編寫動態SQL語句。 (8)提供映射標簽,支持對象與數據庫的ORM字段關系映射。 (9)提供對象關系映射標簽,支持對象關系組建維護。 2、MyBatis框架的缺點:
(1)SQL語句的編寫工作量較大,尤其是字段多、關聯表多時,更是如此,對開發人員編寫SQL語句的功底有一定要求。 (2)SQL語句依賴于數據庫,導致數據庫移植性差,不能隨意更換數據庫。
mybatis和hibernate有什么區別?
Hibernate的優點:
1、hibernate是全自動,hibernate完全可以通過對象關系模型實現對數據庫的操作,擁有完整的JavaBean對象與數據庫的映射結構來自動生成sql。
2、功能強大,數據庫無關性好,O/R映射能力強,需要寫的代碼很少,開發速度很快。
3、有更好的二級緩存機制,可以使用第三方緩存。
4、數據庫移植性良好。
5、hibernate擁有完整的日志系統,hibernate日志系統非常健全,涉及廣泛,包括sql記錄、關系異常、優化警告、緩存提示、臟數據警告等
Hibernate的缺點:
1、學習門檻高,精通門檻更高,程序員如何設計O/R映射,在性能和對象模型之間如何取得平衡,以及怎樣用好Hibernate方面需要的經驗和能力都很強才行
2、hibernate的sql很多都是自動生成的,無法直接維護sql;雖然有hql查詢,但功能還是不及sql強大,見到報表等變態需求時,hql查詢要虛,也就是說hql查詢是有局限的;hibernate雖然也支持原生sql查詢,但開發模式上卻與orm不同,需要轉換思維,因此使用上有些不方便。總之寫sql的靈活度上hibernate不及mybatis。
Mybatis的優點:
1、易于上手和掌握,提供了數據庫查詢的自動對象綁定功能,而且延續了很好的SQL使用經驗,對于沒有那么高的對象模型要求的項目來說,相當完美。
2、sql寫在xml里,便于統一管理和優化, 解除sql與程序代碼的耦合。
3、提供映射標簽,支持對象與數據庫的orm字段關系映射
4、 提供對象關系映射標簽,支持對象關系組建維護
5、提供xml標簽,支持編寫動態sql。
6、速度相對于Hibernate的速度較快
Mybatis的缺點:
1、關聯表多時,字段多的時候,sql工作量很大。
2、sql依賴于數據庫,導致數據庫移植性差。
3、由于xml里標簽id必須唯一,導致DAO中方法不支持方法重載。
4、對象關系映射標簽和字段映射標簽僅僅是對映射關系的描述,具體實現仍然依賴于sql。
5、DAO層過于簡單,對象組裝的工作量較大。
6、不支持級聯更新、級聯刪除。
7、Mybatis的日志除了基本記錄功能外,其它功能薄弱很多。
8、編寫動態sql時,不方便調試,尤其邏輯復雜時。
9、提供的寫動態sql的xml標簽功能簡單,編寫動態sql仍然受限,且可讀性低。
mybatis中#{}和${}的區別是什么?
a、#{}是預編譯處理,${}是字符串替換。 b、Mybatis 在處理#{}時,會將 sql 中的#{}替換為?號,調用 PreparedStatement 的 set 方法來賦值; c、Mybatis 在處理${}時,就是把${}替換成變量的值。 d、使用#{}可以有效的防止 SQL 注入,提高系統安全性
簡述一下mybatis插件運行原理及開發流程?(插件四大天王)
mybatis只支持針對ParameterHandler、ResultSetHandler、StatementHandler、Executor這四種接口的插件,mybatis使用jdk的動態代理,為需要攔截的接口生成代理對象以實現接口方法攔截功能,每當執行這四種接口對象的方法時,就會進入攔截方法,具體就是InvocationHandler的invoke方法,攔截那些你指定需要攔截的方法。
編寫插件:實現Mybatis的Interceptor接口并復寫intercept方法啊,然后給插件編寫注解,指定要攔截哪一個接口的哪些方法,在配置文件中配置編寫的插件即可。
@Intercepts({@Signature(type = StatementHandler.class,method = "parameterize",args = Statement.class)})
插件開發流程:
-
創建自定義攔截器類,實現
org.apache.ibatis.plugin.Interceptor
接口,并重寫其中的intercept()
和plugin()
方法。intercept()
方法用于定義自定義邏輯,plugin()
方法用于生成代理對象。 -
在攔截器類上使用
@Intercepts
注解,尋找需要攔截的方法。 -
在MyBatis的配置文件(通常是
mybatis-config.xml
)中,配置自定義攔截器。 -
創建插件類,繼承
org.apache.ibatis.plugin.PluginAdapter
類,并實現其中的setProperties()
方法。 -
在插件類上使用
@Signature
注解,指定要攔截的方法簽名。 -
編寫一個類,實現
org.apache.ibatis.session.Configuration
接口,重寫其中的addInterceptor()
方法,在方法中添加自定義插件。 -
在MyBatis的配置文件中,使用
<configuration>
標簽的<settings>
子標簽,并指定使用自定義的配置類。 -
調用MyBatis的API進行數據庫操作時,插件將被自動執行。
mybatis的mapper沒有實現類
在 MyBatis 中,Mapper 接口可以不需要對應的實現類,因為 MyBatis 會自動為 Mapper 接口生成代理對象,并實現接口中定義的方法。這種方式稱為 Mapper 接口的動態代理。
當 Mapper 接口沒有對應的實現類時,MyBatis 在運行時會動態生成一個代理對象,該代理對象會攔截接口方法的調用,并根據接口方法的定義將對應的 SQL 語句進行執行。這樣就實現了 Mapper 接口與 SQL 語句的綁定。
在 Mapper 接口中,通常會使用注解或 XML 文件來定義 SQL 語句。例如,使用注解方式定義 SQL 語句的 Mapper 接口示例:
```java
public interface UserMapper {
? ? @Select("SELECT * FROM users WHERE id = #{id}")
? ? User selectUserById(Long id);
}
```
而使用 XML 文件定義 SQL 語句的 Mapper 接口示例:
```java
public interface UserMapper {
? ? User selectUserById(Long id);
}
```
```xml
<!-- UserMapper.xml -->
<mapper namespace="com.example.UserMapper">
? ? <select id="selectUserById" resultType="com.example.User">
? ? ? ? SELECT * FROM users WHERE id = #{id}
? ? </select>
</mapper>
```
當應用程序調用 Mapper 接口中的方法時,MyBatis 會根據方法的定義(注解或 XML 文件中的配置)來執行對應的 SQL 語句,將查詢結果映射為 Java 對象并返回給調用方。
總結來說,即使 Mapper 接口沒有對應的實現類,MyBatis 也能通過動態代理的方式實現接口與 SQL 語句的綁定,使開發人員可以方便地以接口的方式來操作數據庫,提高了開發效率和代碼的可維護性。
MyBatis 與 Spring 框架整合
在將 MyBatis 與 Spring 框架整合時,需要配置 Spring 的 ApplicationContext,并將 MyBatis 的 SqlSessionFactory 注入到 Spring 的容器中,以便讓 Spring 管理 MyBatis 的 SqlSessionFactory,并能夠進行事務管理、異常處理等操作。下面是將 MyBatis 與 Spring 整合的一般步驟:
1. **配置 MyBatis 的 SqlSessionFactoryBean:** 在 Spring 的配置文件中配置 MyBatis 的 SqlSessionFactoryBean,用于創建 MyBatis 的 SqlSessionFactory 實例,并配置數據源、Mapper 接口掃描等信息。
```xml
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
? ? <property name="dataSource" ref="dataSource" />
? ? <property name="mapperLocations" value="classpath:com/example/mappers/*.xml" />
</bean>
```
2. **配置 MyBatis 的 MapperScannerConfigurer:** 使用 MapperScannerConfigurer 配置自動掃描 Mapper 接口,并將其注冊為 Spring 的 Bean。
```xml
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
? ? <property name="basePackage" value="com.example.mappers" />
</bean>
```
3. **配置事務管理器和動態代理**:配置事務管理器(如 DataSourceTransactionManager)以及 MyBatis 的 Mapper Bean 動態代理。
```xml
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
? ? <property name="dataSource" ref="dataSource" />
</bean>
<bean class="org.mybatis.spring.mapper.MapperFactoryBean">
? ? <property name="sqlSessionFactory" ref="sqlSessionFactory" />
? ? <property name="mapperInterface" value="com.example.UserMapper" />
</bean>
```
4. **在業務邏輯中使用 Mapper 接口:** 在業務邏輯的 Spring Bean 中注入 Mapper 接口,然后就可以通過 Mapper 接口來執行 SQL 操作。
```java
@Autowired
private UserMapper userMapper;
```
5. **配置數據源和其他必要的 Bean:** 還需要配置數據源、事務管理器等其它必要的 Bean,用于 MyBatis 與數據庫的交互和事務管理。
通過以上步驟,將 MyBatis 與 Spring 整合后,就可以在 Spring 的應用程序中方便地使用 MyBatis 來操作數據庫,實現數據訪問層的功能。整合的過程主要是通過配置 Spring 的配置文件來管理 MyBatis 的相關 Bean,并利用 Spring 的依賴注入來獲取需要的組件,從而實現 MyBatis 與 Spring 的無縫整合。
MyBatis 緩存
MyBatis 是一個流行的持久層框架,用于對數據庫進行操作。MyBatis 提供了一級緩存和二級緩存來優化數據庫訪問,提高系統性能。
一級緩存: 一級緩存是 MyBatis 中默認開啟的緩存,它指的是 SqlSession 級別的緩存。當查詢完數據后,數據將會保存在 SqlSession 的緩存中,后續對同一條數據的查詢將不會再訪問數據庫,而是直接從緩存中獲取。一級緩存的作用域是當前 SqlSession,在同一個 SqlSession 中進行的多次查詢可以共享一級緩存。
二級緩存: 二級緩存是 MyBatis 的全局緩存,它作用于 SqlSessionFactory 級別,可以被同一個數據庫的不同 SqlSession 所共享。這意味著當不同的 SqlSession 執行相同的 SQL 查詢時,可以從二級緩存中獲取數據,而不必再次訪問數據庫。需要注意的是,二級緩存是跨 SqlSession 的,如果在一個 SqlSession 中更新了數據,會清空二級緩存中與該數據相關的數據,保證緩存的一致性。
啟用二級緩存的步驟包括:
-
在 MyBatis 的配置文件中開啟二級緩存:
<settings><setting name="cacheEnabled" value="true"/> </settings>
-
針對需要使用二級緩存的映射文件,添加
<cache/>
標簽:<mapper namespace="com.example.UserMapper"><cache/><!-- 其他映射配置 --> </mapper>
需要注意的是,當配置了二級緩存后,需要在需要共享緩存的實體類中通過 <cache/>
標簽明確指定是否開啟二級緩存,因為默認情況下是關閉的。并且需要確保相關的實體類實現了 Serializable 接口。因為二級緩存默認使用 Java 的序列化機制進行對象的序列化和反序列化。
總的來說,一級緩存和二級緩存在 MyBatis 中是用來提升查詢性能的重要機制。一級緩存作用于 SqlSession 級別,適用于短生命周期的對象,而二級緩存作用于 SqlSessionFactory 級別,適用于長生命周期的對象,可以在不同 SqlSession 之間共享緩存,但需要注意數據的一致性。
Mybatis是如何進行分頁的?分頁插件的原理是什么?
Mybatis使用RowBounds對象進行分頁,它是針對ResultSet結果集執行的內存分頁,而非物理分頁,可以在sql內直接書寫帶有物理分頁的參數來完成物理分頁功能,也可以使用分頁插件來完成物理分頁。
分頁插件的基本原理是使用Mybatis提供的插件接口,實現自定義插件,在插件的攔截方法內攔截待執行的sql,然后重寫sql,根據dialect方言,添加對應的物理分頁語句和物理分頁參數。
舉例:select * from student,攔截sql后重寫為:select t.* from (select * from student) t limit 0, 10
MyBatis編程步驟是什么樣的?
1、 創建SqlSessionFactory
2、 通過SqlSessionFactory創建SqlSession
3、 通過sqlsession執行數據庫操作
4、 調用session.commit()提交事務
5、 調用session.close()關閉會話
?
Mybatis都有哪些Executor執行器?它們之間的區別是什么?
Mybatis有三種基本的Executor執行器,SimpleExecutor、ReuseExecutor、BatchExecutor。
SimpleExecutor:每執行一次update或select,就開啟一個Statement對象,用完立刻關閉Statement對象。
ReuseExecutor:執行update或select,以sql作為key查找Statement對象,存在就使用,不存在就創建,用完后,不關閉Statement對象,而是放置于Map<String, Statement>內,供下一次使用。簡言之,就是重復使用Statement對象。
BatchExecutor:執行update(沒有select,JDBC批處理不支持select),將所有sql都添加到批處理中(addBatch()),等待統一執行(executeBatch()),它緩存了多個Statement對象,每個Statement對象都是addBatch()完畢后,等待逐一執行executeBatch()批處理。與JDBC批處理相同。
作用范圍:Executor的這些特點,都嚴格限制在SqlSession生命周期范圍內。
模糊查詢like語句該怎么寫
(1)’%${question}%’ 可能引起SQL注入,不推薦
(2)"%"#{question}"%" 注意:因為#{…}解析成sql語句時候,會在變量外側自動加單引號’ ',所以這里 % 需要使用雙引號" ",不能使用單引號 ’ ',不然會查不到任何結果。
(3)CONCAT(’%’,#{question},’%’) 使用CONCAT()函數,推薦
(4)使用bind標簽
<select id="listUserLikeUsername" resultType="com.jourwon.pojo.User">
<bind name="pattern" value="'%' + username + '%'" />
select id,sex,age,username,password from person where username LIKE #{pattern}
</select>
在mapper中如何傳遞多個參數
方法1:順序傳參法
public User selectUser(String name, int deptId);
<select id="selectUser" resultMap="UserResultMap">
? ? select * from user
? ? where user_name = #{0} and dept_id = #{1}
</select>
#{}里面的數字代表傳入參數的順序。
這種方法不建議使用,sql層表達不直觀,且一旦順序調整容易出錯。
方法2:@Param注解傳參法
public User selectUser(@Param("userName") String name, int @Param("deptId") deptId);
<select id="selectUser" resultMap="UserResultMap">
? ? select * from user
? ? where user_name = #{userName} and dept_id = #{deptId}
</select>
#{}里面的名稱對應的是注解@Param括號里面修飾的名稱。
這種方法在參數不多的情況還是比較直觀的,推薦使用。
方法3:Map傳參法
public User selectUser(Map<String, Object> params);
<select id="selectUser" parameterType="java.util.Map" resultMap="UserResultMap">
? ? select * from user
? ? where user_name = #{userName} and dept_id = #{deptId}
</select>
#{}里面的名稱對應的是Map里面的key名稱。
這種方法適合傳遞多個參數,且參數易變能靈活傳遞的情況。
方法4:Java Bean傳參法
public User selectUser(User user);
<select id="selectUser" parameterType="com.jourwon.pojo.User" resultMap="UserResultMap">
? ? select * from user
? ? where user_name = #{userName} and dept_id = #{deptId}
</select>
#{}里面的名稱對應的是User類里面的成員屬性。
這種方法直觀,需要建一個實體類,擴展不容易,需要加屬性,但代碼可讀性強,業務邏輯處理方便,推薦使用。
Mybatis如何執行批量操作
使用foreach標簽
foreach的主要用在構建in條件中,它可以在SQL語句中進行迭代一個集合。foreach標簽的屬性主要有item,index,collection,open,separator,close。
item 表示集合中每一個元素進行迭代時的別名,隨便起的變量名;
index 指定一個名字,用于表示在迭代過程中,每次迭代到的位置,不常用;
open 表示該語句以什么開始,常用“(”;
separator表示在每次進行迭代之間以什么符號作為分隔符,常用“,”;
close 表示以什么結束,常用“)”。
在使用foreach的時候最關鍵的也是最容易出錯的就是collection屬性,該屬性是必須指定的,但是在不同情況下,該屬性的值是不一樣的,主要有一下3種情況:
如果傳入的是單參數且參數類型是一個List的時候,collection屬性值為list
如果傳入的是單參數且參數類型是一個array數組的時候,collection的屬性值為array
如果傳入的參數是多個的時候,我們就需要把它們封裝成一個Map了,當然單參數也可以封裝成map,實際上如果你在傳入參數的時候,在MyBatis里面也是會把它封裝成一個Map的,
map的key就是參數名,所以這個時候collection屬性值就是傳入的List或array對象在自己封裝的map里面的key
具體用法如下:
<!-- 批量保存(foreach插入多條數據兩種方法)
? ? ? ?int addEmpsBatch(@Param("emps") List<Employee> emps); -->
<!-- MySQL下批量保存,可以foreach遍歷 mysql支持values(),(),()語法 --> //推薦使用
<insert id="addEmpsBatch">
? ? INSERT INTO emp(ename,gender,email,did)
? ? VALUES
? ? <foreach collection="emps" item="emp" separator=",">
? ? ? ? (#{emp.eName},#{emp.gender},#{emp.email},#{emp.dept.id})
? ? </foreach>
</insert>
<!-- 這種方式需要數據庫連接屬性allowMutiQueries=true的支持
?如jdbc.url=jdbc:mysql://localhost:3306/mybatis?allowMultiQueries=true --> ?
<insert id="addEmpsBatch">
? ? <foreach collection="emps" item="emp" separator=";"> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
? ? ? ? INSERT INTO emp(ename,gender,email,did)
? ? ? ? VALUES(#{emp.eName},#{emp.gender},#{emp.email},#{emp.dept.id})
? ? </foreach>
</insert>
在 MyBatis 中進行一對一和一對多的關聯查詢
在 MyBatis 中實現一對一和一對多的關聯查詢,通常有以下幾種方式:
### 一對一關聯查詢的實現方式:
1. **嵌套查詢(Nested Queries):** 在父查詢中通過嵌套查詢子查詢來獲取關聯對象的信息。
2. **嵌套結果(Nested Results):** 在 SQL 查詢語句中通過使用嵌套 Select 語句實現一對一關聯查詢。
3. **嵌套映射(Nested Mapping):** 通過在 ResultMap 中定義嵌套的 ResultMap 來實現一對一關聯查詢。
下面是一種常見的嵌套查詢方式的操作步驟:
1. 在 SQL Mapper XML 文件中配置:
?
<!-- 查詢訂單信息,并關聯查詢用戶信息 -->
<select id="selectOrderWithUser" resultMap="orderUserResultMap">SELECT o.*, u.id as user_id, u.username as user_username, u.email as user_emailFROM orders oINNER JOIN users u ON o.user_id = u.idWHERE o.id = #{orderId}
</select><!-- 定義 ResultMap -->
<resultMap id="orderUserResultMap" type="Order"><id property="id" column="id" /><association property="user" resultMap="userResultMap" />
</resultMap><resultMap id="userResultMap" type="User"><id property="id" column="user_id"/><result property="username" column="user_username" /><result property="email" column="user_email" />
</resultMap>
?2. 在 Mapper 接口中定義方法:
Order selectOrderWithUser(Long orderId);
?
?3. 在 Service 層調用 Mapper 中定義的方法:
Order order = orderMapper.selectOrderWithUser(orderId);
?
一對多關聯查詢的實現方式:
1. **嵌套查詢:** 使用多條 SQL 查詢語句來獲取一對多關聯的數據。
2. **嵌套結果:** 在 SQL 查詢語句中使用 Join 等方式,將一對多關聯的數據合并在查詢結果中。
3. **嵌套映射:** 通過在 ResultMap 中定義 Collection 來實現一對多關聯查詢。
下面是一種常見的嵌套查詢方式的操作步驟:
1. 在 SQL Mapper XML 文件中配置:
<!-- 查詢部門信息,并關聯查詢所有員工信息 -->
<select id="selectDepartmentWithEmployees" resultMap="departmentEmployeesResultMap">SELECT d.id as department_id, d.name as department_name,e.id as employee_id, e.name as employee_name, e.email as employee_emailFROM departments dLEFT JOIN employees e ON d.id = e.department_idWHERE d.id = #{departmentId}
</select><!-- 定義 ResultMap -->
<resultMap id="departmentEmployeesResultMap" type="Department"><id property="id" column="department_id" /><result property="name" column="department_name" /><collection property="employees" ofType="Employee"><id property="id" column="employee_id"/><result property="name" column="employee_name"/><result property="email" column="employee_email"/></collection>
</resultMap>
?
?2. 在 Mapper 接口中定義方法:
Department selectDepartmentWithEmployees(Long departmentId);
?
3. 在 Service 層調用 Mapper 中定義的方法:
Department department = departmentMapper.selectDepartmentWithEmployees(departmentId);
?
通過以上方式,可以實現在 MyBatis 中進行一對一和一對多的關聯查詢,具體的方式可以根據實際業務需求和數據結構選擇最適合的方式進行操作。
?
Select * 的缺點
1. 不需要的列會增加數據傳輸時間和網絡開銷
用“SELECT * ”數據庫需要解析更多的對象、字段、權限、屬性等相關內容,在 SQL 語句復雜,硬解析較多的情況下,會對數據庫造成沉重的負擔。
增大網絡開銷;* 有時會誤帶上如log、IconMD5之類的無用且大文本字段,數據傳輸size會幾何增漲。如果DB和應用程序不在同一臺機器,這種開銷非常明顯
即使 mysql 服務器和客戶端是在同一臺機器上,使用的協議還是 tcp,通信也是需要額外的時間。
2. 對于無用的大字段,如 varchar、blob、text,會增加 io 操作
準確來說,長度超過 728 字節的時候,會先把超出的數據序列化到另外一個地方,因此讀取這條記錄會增加一次 io 操作。(MySQL InnoDB)
3. 失去MySQL優化器“覆蓋索引”策略優化的可能性
SELECT * 杜絕了覆蓋索引的可能性,而基于MySQL優化器的“覆蓋索引”策略又是速度極快,效率極高,業界極為推薦的查詢優化方式
select count(*)和select count(1)的區別
1、 一般情況下,Select Count (*)和Select Count(1)兩著返回結果是一樣的
2、 假如表沒有主鍵(Primary key), 那么count(1)比count(*)快,
3、 如果有主鍵的話,那主鍵作為count的條件時候count(主鍵)最快
4、 如果你的表只有一個字段的話那count(*)就是最快的
5、count(*) 跟 count(1) 的結果一樣,都包括對NULL的統計,而count(column) 是不包括NULL的統計
左連接 left Join 右連接,內連接
在 MySQL 中,左連接(LEFT JOIN)、右連接(RIGHT JOIN)和內連接(INNER JOIN)是 SQL 中常用的連接類型,它們的定義與區別如下:
### 1. 左連接(LEFT JOIN):
- 左連接是從左表(左邊)返回所有匹配左表的行,并返回右表中與左表匹配的行,如果右表中沒有匹配的行,則顯示為 NULL 值。
- 語法:`SELECT * FROM 左表 LEFT JOIN 右表 ON 左表.列 = 右表.列;`
- 左表中的所有行都會顯示在結果集中,右表中沒有匹配的行會被填充為 NULL 值。
### 2. 右連接(RIGHT JOIN):
- 右連接是從右表(右邊)返回所有匹配右表的行,并返回左表中與右表匹配的行,如果左表中沒有匹配的行,則顯示為 NULL 值。
- 語法:`SELECT * FROM 左表 RIGHT JOIN 右表 ON 左表.列 = 右表.列;`
- 右表中的所有行都會顯示在結果集中,左表中沒有匹配的行會被填充為 NULL 值。
### 3. 內連接(INNER JOIN):
- 內連接是返回匹配兩個表中行的行,并丟棄不匹配的行,即兩個表中連接條件不符合的行會被過濾掉。
- 語法:`SELECT * FROM 表1 INNER JOIN 表2 ON 表1.列 = 表2.列;`
- 只返回兩個表中連接條件符合的行,不匹配的行不會顯示在結果集中。
### 區別總結:
- 左連接返回左表中所有行以及與左表匹配的右表行,右連接返回右表中所有行以及與右表匹配的左表行,內連接只返回兩個表中連接條件符合的行。
- 三種連接方式都可以通過 `ON` 子句中指定連接條件,根據實際需求選擇合適的連接方式來獲取所需數據。
在實際應用中,根據具體業務需求和數據關系選擇合適的連接方式,以獲取正確的結果集。
數據庫的五大范式
具體內容如下:
第一范式:無重復列
即在一行中的每一列僅有唯一的值并且具有原子性
第二范式:任意一個字段都只依賴表中的同一字段,或者說,屬性完全依賴于主鍵
即非主鍵列的活動必須完全依賴整個主鍵,主鍵必須有唯一性的元素
第三范式:屬性不能傳遞依賴于主屬性,或者說,屬性不依賴其他非主屬性
即非主鍵列互不依賴
第四范式:禁止主鍵列和非主鍵列一對多關系不受約束
第五范式:將表分割成盡可能小的塊,為了排序在表中所有的冗余
MySql的三種日志及作用
這三種日志在 MySQL 數據庫中扮演著關鍵的角色,它們分別支撐著數據庫的事務持久性、數據一致性和可靠性。
-
Redo Log(重做日志):
-
作用:記錄事務對數據頁所做的修改,在事務提交前就將相關的 Redo log 記錄持久化到磁盤。這樣,在事務提交后即使數據頁還未寫入磁盤,數據庫也能通過 Redo log 進行數據的恢復,保證了事務的持久性。
-
數據一致性和可靠性:重做日志的存在保證了即使在數據庫崩潰或斷電的情況下,提交的事務對數據的修改也不會丟失,從而確保了數據的一致性和可靠性。
-
-
Undo Log(回滾日志):
-
作用:記錄事務執行過程中對數據的舊值,支持事務的回滾和讀取操作的多版本并發控制。當事務執行中需要回滾或讀取之前的版本時,可以通過 Undo log 進行數據的恢復操作。
-
數據一致性和可靠性:Undo log 保證了事務的原子性和一致性,即使事務執行過程中出現錯誤或需要回滾,也能確保數據的一致性和可靠性。
-
-
Binlog(二進制日志):
-
作用:記錄了所有的數據庫修改操作,包括對表的插入、更新、刪除等操作,以及對數據庫結構的變更。Binlog 主要用于數據庫的主從復制、數據恢復、數據遷移等場景。
-
數據一致性和可靠性:通過 Binlog,數據庫可以在分布式系統中實現主從復制,確保不同節點之間的數據一致性和可靠性;同時,通過恢復 Binlog 也能實現對數據庫的數據恢復和數據遷移,保證了數據的可靠性和一致性。
-
綜合來看,通過 Redo log 的持久化、Undo log 的回滾支持和 Binlog 的記錄和傳播,MySQL 服務器保證了數據的一致性和可靠性。這些日志機制都是數據庫引擎和服務器核心的組成部分,確保了數據庫的 ACID 特性,即原子性、一致性、隔離性和持久性。
redo log和binlog區別
-
redo log是屬于innoDB層面,binlog屬于MySQL Server層面的,這樣在數據庫用別的存儲引擎時可以達到一致性的要求。
-
redo log是物理日志,記錄該數據頁更新的內容;binlog是邏輯日志,記錄的是這個更新語句的原始邏輯
-
redo log是循環寫,日志空間大小固定;binlog是追加寫,是指一份寫到一定大小的時候會更換下一個文件,不會覆蓋。
-
binlog可以作為恢復數據使用,主從復制搭建,redo log作為異常宕機或者介質故障后的數據恢復使用。
索引的基本原理
1、為什么要有索引? 一般的應用系統,讀寫比例在10:1左右,而且插入操作和一般的更新操作很少出現性能問題,在生產環境中,我們遇到最多的,也是最容易出問題的,還是一些復雜的查詢操作,因此對查詢語句的優化顯然是重中之重。說起加速查詢,就不得不提到索引了。 2、什么是索引? 索引在MySQL中也叫是一種“鍵”,是存儲引擎用于快速找到記錄的一種數據結構。索引對于良好的性能 非常關鍵,尤其是當表中的數據量越來越大時,索引對于性能的影響愈發重要。 索引優化應該是對查詢性能優化最有效的手段了。索引能夠輕易將查詢性能提高好幾個數量級。 索引相當于字典的音序表,如果要查某個字,如果不使用音序表,則需要從幾百頁中逐頁去查。
3、索引的原理
索引的目的在于提高查詢效率,與我們查閱圖書所用的目錄是一個道理:先定位到章,然后定位到該章下的一個小節,然后找到頁數。相似的例子還有:查字典,查火車車次,飛機航班等
本質都是:通過不斷地縮小想要獲取數據的范圍來篩選出最終想要的結果,同時把隨機的事件變成順序的事件,也就是說,有了這種索引機制,我們可以總是用同一種查找方式來鎖定數據。
數據庫也是一樣,但顯然要復雜的多,因為不僅面臨著等值查詢,還有范圍查詢(>、<、between、in)、模糊查詢(like)、并集查詢(or)等等。數據庫應該選擇怎么樣的方式來應對所有的問題呢?我們回想字典的例子,能不能把數據分成段,然后分段查詢呢?最簡單的如果1000條數據,1到100分成第一段,101到200分成第二段,201到300分成第三段…這樣查第250條數據,只要找第三段就可以了,一下子去除了90%的無效數據。但如果是1千萬的記錄呢,分成幾段比較好?按照搜索樹的模型,其平均復雜度是lgN,具有不錯的查詢性能。但這里我們忽略了一個關鍵的問題,復雜度模型是基于每次相同的操作成本來考慮的。而數據庫實現比較復雜,一方面數據是保存在磁盤上的,另外一方面為了提高性能,每次又可以把部分數據讀入內存來計算,因為我們知道訪問磁盤的成本大概是訪問內存的十萬倍左右,所以簡單的搜索樹難以滿足復雜的應用場景。
4、索引的數據結構
MySQL主要用到兩種結構:B+ Tree索引和Hash索引 Inodb存儲引擎 默認是 B+Tree索引 Memory 存儲引擎 默認 Hash索引; MySQL中,只有Memory(Memory表只存在內存中,斷電會消失,適用于臨時表)存儲引擎顯示支持Hash索引,是Memory表的默認索引類型,盡管Memory表也可以使用B+Tree索引。Hash索引把數據以hash形式組織起來,因此當查找某一條記錄的時候,速度非常快。但是因為hash結構,每個鍵只對應一個值,而且是散列的方式分布。所以它并不支持范圍查找和排序等功能。 B+Tree是mysql使用最頻繁的一個索引數據結構,是InnoDB和MyISAM存儲引擎模式的索引類型。相對Hash索引,B+Tree在查找單條記錄的速度比不上Hash索引,但是因為更適合排序等操作,所以它更受歡迎。畢竟不可能只對數據庫進行單條記錄的操作。 對比: hash類型的索引:查詢單條快,范圍查詢慢 btree類型的索引:b+樹,層數越多,數據量指數級增長(我們就用它,因為innodb默認支持它)
B+ 樹索引結構
在 MySQL 中,B+ 樹(B+ Tree)是一種常用的索引結構,用于加速數據庫表的數據查找操作。下面詳細講解 MySQL 中的 B+ 樹索引結構以及選擇它的原因:
### 1. B+ 樹索引結構:
- **結構特點:**
? - B+ 樹是一種平衡多路搜索樹,具有樹形結構,每個節點可以包含多個子節點。
? - 每個非葉子節點存儲索引字段和指向子節點的指針,葉子節點存儲索引字段和指向數據行的指針。
? - 葉子節點按順序連接形成一個有序鏈表,方便范圍查詢操作。
- **查找過程:**
? - 從根節點開始,根據節點中的索引值進行比較,沿著合適的路徑向下查找,直到找到葉子節點。
? - 在葉子節點中進行精確查找或范圍查找,找到對應的數據行。
### 2. 為什么選擇 B+ 樹索引結構:
- **高效的檢索性能:** B+ 樹是一種高效的索引結構,其查詢的時間復雜度為 O(logN),可以快速定位到指定數據行,適用于大數據量數據庫表的索引。
- **有序性和范圍查詢:** B+ 樹的葉子節點形成有序鏈表,適合范圍查詢操作,能夠快速定位到指定范圍的數據行。
- **支持高效的插入和刪除操作:** B+ 樹的平衡性和節點分裂合并策略可以保持樹的平衡,保證高效的插入和刪除操作。
- **適合磁盤存儲:** B+ 樹的節點通常比較大,可以減少磁盤 I/O 次數,適合磁盤存儲的數據庫系統。
- **支持索引順序遍歷:** B+ 樹的葉子節點形成有序鏈表,可以支持索引的順序遍歷,提高查詢性能。
- **適合范圍查詢和排序:** B+ 樹的有序性和范圍查詢優勢,使其適合在 MySQL 數據庫中用于支持范圍查詢、排序操作。
綜上所述,MySQL 選擇 B+ 樹作為索引結構的原因是因為它能夠提供高效的檢索性能、有序性以支持范圍查詢、適合磁盤存儲、支持高效的插入和刪除操作等特點,能夠滿足數據庫系統對索引結構的需求,提高數據庫表的查詢性能和效率。
索引的最左匹配原則
最左匹配原則是指在復合索引中,MySQL會按照索引的最左列開始匹配查詢條件,然后逐漸向右匹配。只有當查詢條件中連續的列滿足了索引的最左前綴時,索引才能被充分利用。以下是一些例子來說明最左匹配原則:
-
假設有一個復合索引
(column1, column2, column3)
。-
有效的查詢條件示例:
WHERE column1 = 'A'
-
無效的查詢條件示例:
WHERE column2 = 'B'
,因為沒有匹配到索引的最左列column1
-
-
假設有一個復合索引
(column1, column2)
。-
有效的查詢條件示例:
WHERE column1 = 'A'
-
有效的查詢條件示例:
WHERE column1 = 'A' AND column2 = 'B'
-
無效的查詢條件示例:
WHERE column2 = 'B'
,因為沒有匹配到索引的最左列column1
-
-
假設有一個復合索引
(column1, column2)
。-
有效的查詢條件示例:
WHERE column1 > 'A'
-
無效的查詢條件示例:
WHERE column2 > 'B'
,因為沒有匹配到索引的最左列column1
-
-
最左前綴匹配原則,非常重要的原則,mysql會一直向右匹配直到遇到范圍查詢(>、<、between、like)就停止匹配,比如a = 1 and b = 2 and c > 3 and d = 4 如果建立(a,b,c,d)順序的索引,d是用不到索引的,如果建立(a,b,d,c)的索引則都可以用到,a,b,d的順序可以任意調整。 =和in可以亂序,比如a = 1 and b = 2 and c = 3 建立(a,b,c)索引可以任意順序,mysql的查詢優化器會幫你優化成索引可以識別的形式
總結起來,最左匹配原則適用于以下情況:
-
查詢條件從索引的最左列開始,連續向右匹配索引列。
-
查詢條件中的列滿足了索引的最左前綴。
如果查詢條件不符合以上兩個條件,那么最左匹配原則將失效,MySQL將無法充分利用復合索引。
在設計和優化索引時,了解最左匹配原則是很有幫助的。它可以幫助你合理地選擇索引列的順序,以提高查詢性能和索引的利用率。
mysql聚簇和非聚簇索引的區別是什么?
mysql的索引類型跟存儲引擎是相關的,innodb存儲引擎數據文件跟索引文件全部放在ibd文件中,而myisam的數據文件放在myd文件中,索引放在myi文件中,其實區分聚簇索引和非聚簇索引非常簡單,只要判斷數據跟索引是否存儲在一起就可以了。
innodb存儲引擎在進行數據插入的時候,數據必須要跟索引放在一起,如果有主鍵就使用主鍵,沒有主鍵就使用唯一鍵,沒有唯一鍵就使用6字節的rowid,因此跟數據綁定在一起的就是聚簇索引,而為了避免數據冗余存儲,其他的索引的葉子節點中存儲的都是聚簇索引的key值,因此innodb中既有聚簇索引也有非聚簇索引,而myisam中只有非聚簇索引。
mysql索引結構有哪些,各自的優劣是什么?
索引的數據結構和具體存儲引擎的實現有關,mysql中使用較多的索引有hash索引,B+樹索引,innodb的索引實現為B+樹,memory存儲引擎為hash索引。
B+樹是一個平衡的多叉樹,從根節點到每個葉子節點的高度差值不超過1,而且同層級的二節點間有指針相關連接,在B+樹上的常規檢索,從根節點到葉子節點的搜索效率基本相當,不會出現大幅波動,而且基于索引的順序掃描時,也可以利用雙向指針快速左右移動,效率非常高。因為,B+樹索引被廣泛應用于數據庫、文件系統等場景。
哈希索引就是采用一定的哈希算法,把鍵值換算成新的哈希值,檢索時不需要類似B+樹那樣從根節點到葉子節點逐級查找,只需一次哈希算法即可立刻定位到相應的位置,速度非常快。
如果是等值查詢,那么哈希索引明顯有絕對優勢,因為只需要經過一次算法即可找到相應的鍵值,前提是鍵值都是唯一的。如果鍵值不是唯一的,就需要先找到該鍵所在位置,然后再根據鏈表往后掃描,知道找到對應的數據
如果是范圍查詢檢索,這時候哈徐索引就毫無用武之地了,因為原先是有序的鍵值,經過哈希算法后,有可能變成不連續的了,就沒辦法再利用索引完成范圍查詢檢索
哈希所有也沒辦法利用索引完成排序,以及like這樣的部分模糊查詢
哈希索引也不支持多列聯合索引的最左匹配規則
B+樹索引的關鍵字檢索效率比較平均,不像B樹那樣波動大,在有大量重復鍵值情況下,哈希索引的效率也是極低的,因此存在哈希碰撞問題。
索引的設計原則有哪些?
在數據庫中,創建索引是提高查詢效率和性能的重要手段之一。以下是一些創建索引的原則:
-
選擇合適的列:選擇那些經常用于查詢和連接的列來創建索引。通常包括經常出現在WHERE、JOIN、ORDER BY和GROUP BY子句中的列。
-
避免過度索引:不要為每個列都創建索引,因為索引的維護和存儲會帶來額外的開銷。過多的索引不僅會占用磁盤空間,還可能導致索引失效、降低寫操作的性能等問題。
-
考慮列的選擇性:選擇具有較高選擇性(不重復值較多)的列來創建索引,這樣可以減少索引的大小和搜索的區間。
-
考慮查詢的頻率和重要性:根據查詢的頻率和重要性來選擇創建索引的列。如果某個查詢非常頻繁且對性能要求較高,那么為該查詢常用的列創建索引是很有必要的。
-
綜合考慮查詢和更新的平衡:索引會提高查詢的速度,但會降低更新操作的速度。因此,在創建索引時需要綜合考慮查詢和更新的平衡,選擇適當的索引策略。
-
考慮數據量和存儲空間:索引會占用額外的存儲空間,因此在創建索引時需要考慮數據量的大小。對于較大的表和數據量龐大的表,需要謹慎選擇創建索引的列,以避免過度的存儲開銷。
-
定期維護和更新索引:索引的性能和效果是需要定期維護和更新的。當表的數據發生變化時,如插入、更新或刪除操作,需要及時更新索引以保持索引的有效性。
-
使用復合索引:對于經常同時查詢多個列的情況,可以考慮創建復合索引,即包含多個列的聯合索引。復合索引可以提高查詢效率,并且可以減少索引的數量。
除了以上原則外,創建索引還需要根據具體的數據庫系統和查詢需求做進一步的優化和調整。在進行索引設計時,需要綜合考慮數據庫結構、查詢模式、數據量等因素,以達到提高查詢性能的目的。
在進行索引設計的時候,應該保證索引字段占用的空間越小越好,這只是一個大的方向,還有一些細節點需要注意下:
1、適合索引的列是出現在where字句中的列,或者連接子句中指定的列
2、基數較小的表,索引效果差,沒必要創建索引
3、在選擇索引列的時候,越短越好,可以指定某些列的一部分,沒必要用全部字段的值
4、不要給表中的每一個字段都創建索引,并不是索引越多越好
5、定義有外鍵的數據列一定要創建索引
6、更新頻繁的字段不要有索引
7、創建索引的列不要過多,可以創建組合索引,但是組合索引的列的個數不建議太多
8、大文本、大對象不要創建索引
索引失效的十大原因
索引失效的場景
1、不滿足最左匹配原則
2、索引列上有計算 如:where id+1=2
3、索引列上使用了函數 如:where SUBSTR(name,1,2)=17
4、字段類型不同,如本來是數字類型,結果加上了引號變成了字符串
5、like 左邊加上了%號6、列對比,兩個列在where后面進行比較
7、使用or,如果使用or,前面和后面的列都要加上索引才會生效
8、not in和not exists,如果主鍵索引會走索引,其他不會
9、!= 慎重使用,基本會走全表,Extral中有using where=全表掃描
10、排序列和聯合索引順序不一致
11、排序列包含非一個索引的列
https://www.cnblogs.com/wushaopei/p/12283647.html
什么是回表查詢?
通俗的講就是,如果索引的列在 select 所需獲得的列中(因為在 mysql 中索引是根據索引列的值進行排序的,所以索引節點中存在該列中的部分值)或者根據一次索引查詢就能獲得記錄就不需要回表,如果 select 所需獲得列中有大量的非索引列,索引就需要到表中找到相應的列的信息,這就叫回表。
回表查詢,先定位主鍵值,再定位行記錄,它的性能較掃一遍索引樹更低。
使用聚集索引(主鍵或第一個唯一索引)就不會回表,普通索引就會回表
什么是覆蓋索引?***
通常開發人員會根據查詢的where條件來創建合適的索引,但是優秀的索引設計應該考慮到整個查詢。其實mysql可以使用索引來直接獲取列的數據。如果索引的葉子節點包含了要查詢的數據,那么就不用回表查詢了,也就是說這種索引包含(亦稱覆蓋)所有需要查詢的字段的值,我們稱這種索引為覆蓋索引。
1、索引項通常比記錄要小,所以MySQL訪問更少的數據。
2、索引都按值得大小存儲,相對于隨機訪問記錄,需要更少的I/O。
3、數據引擎能更好的緩存索引,比如MyISAM只緩存索引。
4、覆蓋索引對InnoDB尤其有用,因為InnoDB使用聚集索引組織數據,如果二級索引包含查詢所需的數據,就不再需要在聚集索引中查找了。
限制:
1、覆蓋索引也并不適用于任意的索引類型,索引必須存儲列的值。
2、Hash和full-text索引不存儲值,因此MySQL只能使用BTree。
3、不同的存儲引擎實現覆蓋索引都是不同的,并不是所有的存儲引擎都支持覆蓋索引。
4、如果要使用覆蓋索引,一定要注意SELECT列表值取出需要的列,不可以SELECT * ,因為如果將所有字段一起做索引會導致索引文件過大,查詢性能下降。
索引下推
如果沒有索引下推優化(或稱ICP優化),當進行索引查詢時,首先根據索引來查找記錄,然后再根據where條件來過濾記錄;在支持ICP優化后,MySQL會在取出索引的同時,判斷是否可以進行where條件過濾再進行索引查詢,也就是說提前執行where的部分過濾操作,在某些場景下,可以大大減少回表次數,從而提升整體性能。
mysql鎖的類型有哪些?
基于鎖的屬性分類:共享鎖、排他鎖。
基于鎖的粒度分類:行級鎖(innodb )、表級鎖( innodb 、myisam)、頁級鎖( innodb引擎)、記錄鎖、間隙鎖、臨鍵鎖。
基于鎖的狀態分類:意向共享鎖、意向排它鎖。
共享鎖(share lock): 共享鎖又稱讀鎖,簡稱 S 鎖;當一個事務為數據加上讀鎖之后,其他事務只能對該數據加讀鎖,而不能對數據加寫鎖,直到所有的讀鎖釋放之后其他事務才能對其進行加持寫鎖。共享鎖的特性主要是為了支持并發的讀取數據,讀取數據的時候不支持修改,避免出現重復讀的問題。
排他鎖(exclusive lock):排他鎖又稱寫鎖,簡稱 X 鎖;當一個事務為數據加上寫鎖時,其他請求將不能再為數據加任何鎖,直到該鎖釋放之后,其他事務才能對數據進行加鎖。排他鎖的目的是在數據修改時候,不允許其他人同時修改,也不允許其他人讀取,避免了出現臟數據和臟讀的問題。
表鎖(table lock):表鎖是指上鎖的時候鎖住的是整個表,當下一個事務訪問該表的時候,必須等前一個事務釋放了鎖才能進行對表進行訪問;特點:粒度大,加鎖簡單,容易沖突;
行鎖:行鎖是指上鎖的時候鎖住的是表的某一行或多行記錄,其他事務訪問同一張表時,只有被鎖住的記錄不能訪問,其他的記錄可正常訪問,特點:粒度小,加鎖比表鎖麻煩,不容易沖突,相比表鎖支持的并發要高
記錄鎖(Record lock):記錄鎖也屬于行鎖中的一種,只不過記錄鎖的范圍只是表中的某一條記錄,記錄鎖是說事務在加鎖后鎖住的只是表的某一條記錄,加了記錄鎖之后數據可以避免數據在查詢的時候被修改的重復讀問題,也避免了在修改的事務未提交前被其他事務讀取的臟讀問題
頁鎖:頁級鎖是 MysQL 中鎖定粒度介于行級鎖和表級鎖中間的一種鎖.表級鎖速度快,但沖突多,行級沖突少,但速度慢。所以取了折衷的頁級,一次鎖定相鄰的一組記錄。特點:開銷和加鎖時間界于表鎖和行鎖之間,會出現死鎖;鎖定粒度界于表鎖和行鎖之間,并發度一般。
間隙鎖:是屬于行鎖的一種,間隙鎖是在事務加鎖后其鎖住的是表記錄的某一個區間,當表的相鄰ID之間出現空隙則會形成一個區間,遵循左開右閉原則。范圍查詢并且查詢未命中記錄,查詢條件必須命中索引、間隙鎖只會出現在REPEATABLE_READ(重復讀)的事務級別中。
臨鍵鎖(Next-Key lock):也屬于行鎖的一種,并且它是INNODB的行鎖默認算法,總結來說它就是記錄鎖和間隙鎖的組合,臨鍵鎖會把查詢出來的記錄鎖住,同時也會把該范圍查詢內的所有間隙空間也會鎖住,再之它會把相鄰的下一個區間也會鎖住。
mysql執行計劃怎么看?
在 MySQL 中,可以通過使用 `EXPLAIN` 關鍵字來查看 SQL 語句的執行計劃,幫助優化查詢性能。下面是使用 `EXPLAIN` 查看 MySQL 執行計劃的方法:
### 1. 基本語法:
```sql
EXPLAIN SELECT * FROM your_table WHERE your_condition;
```
?2. 實際操作步驟:
?a. 執行查詢前加上 `EXPLAIN` 關鍵字:
```sql
EXPLAIN SELECT * FROM your_table WHERE your_condition;
```
b. 查看執行計劃結果:
執行以上 SQL 語句后,會返回一張表格,其中包含了關于查詢執行的各種重要信息,例如查詢的優化方式、表的讀取順序、使用的索引、行數估算等。
c. 解讀執行計劃信息:
在執行計劃結果中,可以注意以下一些重要的字段信息:
- **id:** 查詢的順序,如果是子查詢會有多個執行順序。
- **select_type:** 查詢類型,如 SIMPLE、PRIMARY、DERIVED、SUBQUERY 等。
- **table:** 顯示查詢操作涉及的表。
- **type:** 表示 MySQL 在表中找到所需行的方式,常見的類型有 const、eq_ref、ref、range、index、all 等,通常從最好到最差的順序排列。
- **key:** 顯示 MySQL 決定使用哪個索引來優化查詢。
- **rows:** 評估在找到所需行之前要檢查的行數。
- **Extra:** 包含關于查詢執行的額外信息,可能包括使用了索引、臨時表等信息。
?3. 根據執行計劃優化 SQL:
通過查看執行計劃,可以了解 MySQL 數據庫是如何執行你的查詢的,并可以根據執行計劃的信息進行 SQL 語句的調優,例如添加合適的索引、優化表結構、改變查詢方式等,以提高查詢性能和效率。
通過上述方法,你可以使用 `EXPLAIN` 關鍵字來查看 MySQL 的執行計劃,幫助分析和優化查詢語句的執行效率。
事務的基本特性是什么?
事務四大特征:原子性,一致性,隔離性和持久性。
-
原子性(Atomicity) 一個原子事務要么完整執行,要么干脆不執行。這意味著,工作單元中的每項任務都必須正確執行。如果有任一任務執行失敗,則整個工作單元或事務就會被終止。即此前對數據所作的任何修改都將被撤銷。如果所有任務都被成功執行,事務就會被提交,即對數據所作的修改將會是永久性的。
-
一致性(Consistency) 一致性代表了底層數據存儲的完整性。它必須由事務系統和應用開發人員共同來保證。事務系統通過保證事務的原子性,隔離性和持久性來滿足這一要求; 應用開發人員則需要保證數據庫有適當的約束(主鍵,引用完整性等),并且工作單元中所實現的業務邏輯不會導致數據的不一致(即,數據預期所表達的現實業務情況不相一致)。例如,在一次轉賬過程中,從某一賬戶中扣除的金額必須與另一賬戶中存入的金額相等。支付寶賬號100 你讀到余額要取,有人向你轉100 但是事物沒提交(這時候你讀到的余額應該是100,而不是200) 這種就是一致性
-
隔離性(Isolation) 隔離性意味著事務必須在不干擾其他進程或事務的前提下獨立執行。換言之,在事務或工作單元執行完畢之前,其所訪問的數據不能受系統其他部分的影響。
-
持久性(Durability) 持久性表示在某個事務的執行過程中,對數據所作的所有改動都必須在事務成功結束前保存至某種物理存儲設備。這樣可以保證,所作的修改在任何系統癱瘓時不至于丟失。
MySQL的隔離級別有哪些?
MySQL定義了四種隔離級別,包括一些具體規則,用于限定事務內外哪些改變是可見的,哪些改變是不可見的。低級別的隔離一般支持更高的并發處理,并且擁有更低的系統開銷。
READ UNCOMMITTED 讀取未提交內容 在這個隔離級別,所有事務都可以“看到”未提交事務的執行結果。在這種級別上,可能會產生很多問題,除非用戶真的知道自己在做什么,并有很好的理由選擇這樣做。本隔離級別很少用于實際應用,因為它的性能也不必其他性能好多少,而別的級別還有其他更多的優點。讀取未提交數據,也被稱為“臟讀”
READ COMMITTED 讀取提交內容 大多數數據庫系統的默認隔離級別(但是不是MySQL的默認隔離級別),滿足了隔離的早先簡單定義:一個事務開始時,只能“看見”已經提交事務所做的改變,一個事務從開始到提交前,所做的任何數據改變都是不可見的,除非已經提交。這種隔離級別也支持所謂的“不可重復讀”。這意味著用戶運行同一個語句兩次,看到的結果是不同的。
REPEATABLE READ 可重復讀 MySQL數據庫默認的隔離級別。該級別解決了READ UNCOMMITTED隔離級別導致的問題。它保證同一事務的多個實例在并發讀取事務時,會“看到同樣的”數據行。不過,這會導致另外一個棘手問題“幻讀”。InnoDB和Falcon存儲引擎通過多版本并發控制機制解決了幻讀問題。
SERIALIZABLE 可串行化 該級別是最高級別的隔離級。它通過強制事務排序,使之不可能相互沖突,從而解決幻讀問題。簡而言之,SERIALIZABLE是在每個讀的數據行上加鎖。在這個級別,可能導致大量的超時Timeout和鎖競爭Lock Contention現象,實際應用中很少使用到這個級別,但如果用戶的應用為了數據的穩定性,需要強制減少并發的話,也可以選擇這種隔離級。
一級封鎖協議。事務T在修改數據R之前必須先對其加X 鎖 直到事務結束才釋放。可防止丟失修改 二級封鎖協議。一級封鎖協議加上事務T在讀取數據R之前先對其加S鎖,讀完后即可釋放S鎖。可防止丟失修改,還可防止讀“臟”數據 三級封鎖協議。一級封鎖協議加上事務T在讀取數據R之前先對其加S鎖,直到事務結束才釋放。可防止丟失修改、防止讀“臟”數據與防止數據(不可)重復讀
兩段鎖協議。可串行化的。可能發生死鎖
-
臟讀
臟讀是指一個事務讀取了未提交事務執行過程中的數據。 當一個事務的操作正在多次修改數據,而在事務還未提交的時候,另外一個并發事務來讀取了數據,就會導致讀取到的數據并非是最終持久化之后的數據,這個數據就是臟讀的數據。
-
不可重復讀
不可重復讀是指對于數據庫中的某個數據,一個事務執行過程中多次查詢返回不同查詢結果,這就是在事務執行過程中,數據被其他事務提交修改了。 不可重復讀同臟讀的區別在于,臟讀是一個事務讀取了另一未完成的事務執行過程中的數據,而不可重復讀是一個事務執行過程中,另一事務提交并修改了當前事務正在讀取的數據。
-
虛讀(幻讀)
幻讀是事務非獨立執行時發生的一種現象,例如事務T1批量對一個表中某一列列值為1的數據修改為2的變更,但是在這時,事務T2對這張表插入了一條列值為1的數據,并完成提交。此時,如果事務T1查看剛剛完成操作的數據,發現還有一條列值為1的數據沒有進行修改,而這條數據其實是T2剛剛提交插入的,這就是幻讀。 幻讀和不可重復讀都是讀取了另一條已經提交的事務(這點同臟讀不同),所不同的是不可重復讀查詢的都是同一個數據項,而幻讀針對的是一批數據整體(比如數據的個數)。
怎么處理MySQL的慢查詢?
處理 MySQL 的慢查詢可以采取以下幾種方法:
-
使用索引優化:慢查詢通常是由于缺乏或不正確使用索引導致的。通過分析慢查詢的執行計劃,確定應該創建哪些索引來加速查詢。可以使用
EXPLAIN
或EXPLAIN ANALYZE
命令來查看查詢的執行計劃,并使用CREATE INDEX
命令創建適當的索引。 -
優化查詢語句:優化查詢語句的編寫可以顯著提升查詢性能。避免使用全表掃描和不必要的連接操作,盡量簡化查詢條件,并使用合適的查詢語句,如使用
INNER JOIN
替代WHERE
子句中的子查詢。 -
- 確保編寫高效的 SQL 查詢語句,避免不必要的查詢、使用 `SELECT *`、多余的子查詢等。
- 盡量避免在 WHERE 子句中對字段進行函數操作,會影響索引的使用。
- 使用合適的 JOIN 操作,避免笛卡爾積(Cartesian Product)和不必要的連接。
- 限制返回結果集的大小,避免一次性獲取過多數據。 -
調整服務器參數:通過適當設置 MySQL 服務器的參數,可以提升數據庫的性能。例如,增加緩沖區大小(如
innodb_buffer_pool_size
)、優化查詢緩存(如query_cache_size
)和調整并發連接數等。 -
切分大表:如果查詢的表非常大,可以考慮將大表切分為更小的表,在查詢時只查詢所需的分片表,可以減輕單個查詢的負載,提高查詢速度。
-
定期優化和維護數據庫:定期對數據庫進行優化和維護可以提升整體性能。包括定期進行表優化、碎片整理、數據歸檔和備份等操作,以確保數據庫的健康狀態。
-
監控和記錄慢查詢:及時發現和記錄慢查詢是優化的起點。通過開啟慢查詢日志(slow query log)來記錄慢查詢語句,然后根據日志分析找出消耗時間較長的查詢,優化這些查詢可以提高整體性能。
-
使用緩存:對于一些頻繁查詢的數據,可以考慮使用緩存技術,如使用 Redis、Memcached 等緩存服務器緩存查詢結果,減少對數據庫的訪問次數,提高響應速度。
-
使用數據庫連接池:使用數據庫連接池可以減少數據庫連接的開銷,提高并發性能。連接池會管理數據庫連接的獲取和釋放,合理配置連接池參數可以提高數據庫的性能和穩定性。
通過以上方法,可以逐步優化和改進數據庫的慢查詢問題,提升數據庫的性能和響應速度。需要根據具體的業務場景和數據庫配置來選擇和調整優化策略。
ACID是靠什么保證的?
原子性由undolog日志來保證,它記錄了需要回滾的日志信息,事務回滾時撤銷已經執行成功的sql
一致性是由其他三大特性保證,程序代碼要保證業務上的一致性
隔離性是由MVCC來保證
持久性由redolog來保證,mysql修改數據的時候會在redolog中記錄一份日志數據,就算數據沒有保存成功,只要日志保存成功了,數據仍然不會丟失
什么是MVCC?
1、MVCC
MVCC,全稱Multi-Version Concurrency Control,即多版本并發控制。MVCC是一種并發控制的方法,一般在數據庫管理系統中,實現對數據庫的并發訪問,在編程語言中實現事務內存。
MVCC在MySQL InnoDB中的實現主要是為了提高數據庫并發性能,用更好的方式去處理讀寫沖突,做到即使有讀寫沖突時,也能做到不加鎖,非阻塞并發讀。
2、當前讀
像select lock in share mode(共享鎖), select for update ; update, insert ,delete(排他鎖)這些操作都是一種當前讀,為什么叫當前讀?就是它讀取的是記錄的最新版本,讀取時還要保證其他并發事務不能修改當前記錄,會對讀取的記錄進行加鎖。
3、快照讀(提高數據庫的并發查詢能力)
像不加鎖的select操作就是快照讀,即不加鎖的非阻塞讀;快照讀的前提是隔離級別不是串行級別,串行級別下的快照讀會退化成當前讀;之所以出現快照讀的情況,是基于提高并發性能的考慮,快照讀的實現是基于多版本并發控制,即MVCC,可以認為MVCC是行鎖的一個變種,但它在很多情況下,避免了加鎖操作,降低了開銷;既然是基于多版本,即快照讀可能讀到的并不一定是數據的最新版本,而有可能是之前的歷史版本
4、當前讀、快照讀、MVCC關系
MVCC多版本并發控制指的是維持一個數據的多個版本,使得讀寫操作沒有沖突,快照讀是MySQL為實現MVCC的一個非阻塞讀功能。MVCC模塊在MySQL中的具體實現是由三個隱式字段,undo日志、read view三個組件來實現的。
MVCC解決的問題是什么?
數據庫并發場景有三種,分別為:
1、讀讀:不存在任何問題,也不需要并發控制
2、讀寫:有線程安全問題,可能會造成事務隔離性問題,可能遇到臟讀、幻讀、不可重復讀
3、寫寫:有線程安全問題,可能存在更新丟失問題
MVCC是一種用來解決讀寫沖突的無鎖并發控制,也就是為事務分配單項增長的時間戳,為每個修改保存一個版本,版本與事務時間戳關聯,讀操作只讀該事務開始前的數據庫的快照,所以MVCC可以為數據庫解決一下問題:
1、在并發讀寫數據庫時,可以做到在讀操作時不用阻塞寫操作,寫操作也不用阻塞讀操作,提高了數據庫并發讀寫的性能
2、解決臟讀、幻讀、不可重復讀等事務隔離問題,但是不能解決更新丟失問題
MVCC實現原理是什么?
MVCC(Multi-Version Concurrency Control)是一種數據庫并發控制技術,常用于實現事務的隔離性,保證事務之間的并發執行。MVCC 的實現原理主要通過版本控制來實現多個事務并發執行而不會相互影響,常見于像 MySQL、PostgreSQL 等數據庫系統中。
### MVCC 的實現原理如下:
1. **版本控制:** 每次對數據庫的數據進行更新時,并不直接修改原始數據,而是創建新的版本(或稱為快照)來保存被修改的數據。這樣,每個事務在讀取數據時,都會讀取到一個版本的數據,而不會受到其他事務同時修改數據的影響。
2. **事務版本號:** 每個事務有一個唯一的事務版本號,用來標識該事務可以讀取的數據版本。事務在讀取數據時,會根據自己的事務版本號來確定所讀取數據的版本,從而實現事務之間的隔離性。
3. **數據行的版本信息:** 每行數據都會包含版本信息,通常有兩種方式來實現:
? ?- 一種是在數據行中添加版本號字段,用來記錄數據的版本信息;
? ?- 另一種是使用時間戳,記錄數據被修改的時間。
4. **讀取版本判斷:** 當事務讀取數據時,系統會根據事務的版本號和數據的版本信息來判斷是否可以讀取該數據,一般有以下幾種情況:
? ?- 如果數據的版本號在事務開始之前,則可以讀取;
? ?- 如果數據的版本號在事務開始之后,但是數據的更新事務未提交,則根據事務隔離級別確定是否可以讀取。
5. **寫操作處理:** 當事務對數據進行更新時,系統會創建一個新的版本來保存修改后的數據,同時保留原始數據的版本。其他事務在讀取數據時,可以根據版本控制機制來讀取到合適的數據版本。
通過 MVCC 技術,數據庫系統可以實現高并發性和事務隔離性,同時保證數據的一致性。不同的數據庫系統可能會有不同的實現細節,但 MVCC 的核心思想是基于版本控制來實現并發控制。
RC(讀提交內容)、RR(可重復讀)級別下的InnoDB快照讀有什么不同
因為Read View生成時機的不同,從而造成RC、RR級別下快照讀的結果的不同
1、在RR級別下的某個事務的對某條記錄的第一次快照讀會創建一個快照即Read View,將當前系統活躍的其他事務記錄起來,此后在調用快照讀的時候,還是使用的是同一個Read View,所以只要當前事務在其他事務提交更新之前使用過快照讀,那么之后的快照讀使用的都是同一個Read View,所以對之后的修改不可見
2、在RR級別下,快照讀生成Read View時,Read View會記錄此時所有其他活動和事務的快照,這些事務的修改對于當前事務都是不可見的,而早于Read View創建的事務所做的修改均是可見
3、在RC級別下,事務中,每次快照讀都會新生成一個快照和Read View,這就是我們在RC級別下的事務中可以看到別的事務提交的更新的原因。
總結:在RC隔離級別下,是每個快照讀都會生成并獲取最新的Read View,而在RR隔離級別下,則是同一個事務中的第一個快照讀才會創建Read View,之后的快照讀獲取的都是同一個Read View.
什么是mysql的主從復制?
MySQL 主從復制是指數據可以從一個MySQL數據庫服務器主節點復制到一個或多個從節點。MySQL 默認采用異步復制方式,這樣從節點不用一直訪問主服務器來更新自己的數據,數據的更新可以在遠程連接上進行,從節點可以復制主數據庫中的所有數據庫或者特定的數據庫,或者特定的表。
mysql為什么需要主從同步?
1、在業務復雜的系統中,有這么一個情景,有一句sql語句需要鎖表,導致暫時不能使用讀的服務,那么就很影響運行中的業務,使用主從復制,讓主庫負責寫,從庫負責讀,這樣,即使主庫出現了鎖表的情景,通過讀從庫也可以保證業務的正常運作。
2、做數據的熱備
3、架構的擴展。業務量越來越大,I/O訪問頻率過高,單機無法滿足,此時做多庫的存儲,降低磁盤I/O訪問的頻率,提高單個機器的I/O性能。
mysql復制原理是什么?
(1)master服務器將數據的改變記錄二進制binlog日志,當master上的數據發生改變時,則將其改變寫入二進制日志中;
(2)slave服務器會在一定時間間隔內對master二進制日志進行探測其是否發生改變,如果發生改變,則開始一個I/OThread請求master二進制事件
(3)同時主節點為每個I/O線程啟動一個dump線程,用于向其發送二進制事件,并保存至從節點本地的中繼日志中,從節點將啟動SQL線程從中繼日志中讀取二進制日志,在本地重放,使得其數據和主節點的保持一致,最后I/OThread和SQLThread將進入睡眠狀態,等待下一次被喚醒。
也就是說:
-
從庫會生成兩個線程,一個I/O線程,一個SQL線程;
-
I/O線程會去請求主庫的binlog,并將得到的binlog寫到本地的relay-log(中繼日志)文件中;
-
主庫會生成一個log dump線程,用來給從庫I/O線程傳binlog;
-
SQL線程,會讀取relay log文件中的日志,并解析成sql語句逐一執行;
注意:
1--master將操作語句記錄到binlog日志中,然后授予slave遠程連接的權限(master一定要開啟binlog二進制日志功能;通常為了數據安全考慮,slave也開啟binlog功能)
。 2--slave開啟兩個線程:IO線程和SQL線程。其中:IO線程負責讀取master的binlog內容到中繼日志relay log里;SQL線程負責從relay log日志里讀出binlog內容,并更新到slave的數據庫里,這樣就能保證slave數據和master數據保持一致了。
3--Mysql復制至少需要兩個Mysql的服務,當然Mysql服務可以分布在不同的服務器上,也可以在一臺服務器上啟動多個服務。
4--Mysql復制最好確保master和slave服務器上的Mysql版本相同(如果不能滿足版本一致,那么要保證master主節點的版本低于slave從節點的版本) 5--master和slave兩節點間時間需同步
具體步驟:
1、從庫通過手工執行change master to 語句連接主庫,提供了連接的用戶一切條件(user 、password、port、ip),并且讓從庫知道,二進制日志的起點位置(file名 position 號); start slave
2、從庫的IO線程和主庫的dump線程建立連接。
3、從庫根據change master to 語句提供的file名和position號,IO線程向主庫發起binlog的請求。
4、主庫dump線程根據從庫的請求,將本地binlog以events的方式發給從庫IO線程。
5、從庫IO線程接收binlog events,并存放到本地relay-log中,傳送過來的信息,會記錄到master.info中
6、從庫SQL線程應用relay-log,并且把應用過的記錄到relay-log.info中,默認情況下,已經應用過的relay 會自動被清理purge
簡述Myisam和Innodb的區別?
MyISAM和InnoDB是MySQL數據庫中常見的兩種存儲引擎,它們在性能、功能和特性上有一些區別。以下是它們的主要區別:
-
事務支持: MyISAM不支持事務,而InnoDB支持事務。事務是一系列數據庫操作的邏輯單元,可以保證數據的一致性和完整性。對于需要嚴格事務支持的應用,如高并發的OLTP(聯機事務處理)系統,InnoDB更加適合。
-
并發控制: MyISAM使用表級鎖定,即當一個線程對表執行寫操作時,其他線程無法對該表進行寫操作,但可以進行讀操作。而InnoDB使用行級鎖定,允許并發事務讀寫不同的行,提供更好的并發性能。
-
數據完整性: MyISAM不提供外鍵約束,也不支持事務的回滾和崩潰恢復功能。而InnoDB支持外鍵約束,可以保證數據的一致性和完整性,并提供了崩潰恢復和回滾機制。
-
索引類型: MyISAM只支持表級鎖定,對于大量的讀操作和少量的寫操作性能較好。InnoDB使用B+樹索引,支持行級鎖定,對于大量的讀寫操作性能較好。
-
崩潰恢復: MyISAM在崩潰后需要執行修復操作來恢復數據一致性,修復過程相對較慢。而InnoDB通過事務的日志和redolog來實現快速崩潰恢復。
總的來說,MyISAM對于讀操作較多的應用場景和小型網站更適合,而InnoDB適用于需要事務支持、并發性要求高以及數據完整性的應用,特別是對于大型的OLTP系統。在選擇存儲引擎時,需要根據應用的特點和需求進行綜合考慮。
InnoDB存儲引擎: 主要面向OLTP(Online Transaction Processing,在線事務處理)方面的應用,是第一個完整支持ACID事務的存儲引擎(BDB第一個支持事務的存儲引擎,已經停止開發)。 特點:
1 支持行鎖 2 支持外鍵 3 支持自動增加列AUTO_INCREMENT屬性 4 支持事務 5 支持MVCC模式的讀寫 6 讀的效率低于MYISAM 7.寫的效率高優于MYISAM 8.適合頻繁修改以及設計到安全性較高的應用 9.清空整個表的時候,Innodb是一行一行的刪除,
MyISAM存儲引擎: 是MySQL官方提供的存儲引擎,主要面向OLAP(Online Analytical Processing,在線分析處理)方面的應用。
特點:
1 獨立于操作系統,當建立一個MyISAM存儲引擎的表時,就會在本地磁盤建立三個文件,例如我建立tb_demo表,那么會生成以下三個文件tb_demo.frm,tb_demo.MYD,tb_demo.MYI 2 不支持事務, 3 支持表鎖和全文索引 4 MyISAM存儲引擎表由MYD和MYI組成,MYD用來存放數據文件,MYI用來存放索引文件。MySQL數據庫只緩存其索引文件,數據文件的緩存交給操作系統本身來完成; 5 MySQL5.0版本開始,MyISAM默認支持256T的單表數據; 6.選擇密集型的表:MYISAM存儲引擎在篩選大量數據時非常迅速,這是他最突出的優點 7.讀的效率優于InnoDB 8.寫的效率低于InnoDB 9.適合查詢以及插入為主的應用 10.清空整個表的時候,MYISAM則會新建表
簡述mysql中索引類型有哪些,以及對數據庫的性能的影響?
普通索引:允許被索引的數據列包含重復的值
唯一索引:可以保證數據記錄的唯一性
主鍵索引:是一種特殊的唯一索引,在一張表中只能定義一個主鍵索引,主鍵用于唯一標識一條記錄,使用關鍵字primary key來創建
聯合索引:索引可以覆蓋多個數據列
全文索引:通過建立倒排索引,可以極大的提升檢索效率,解決判斷字段是否包含的問題,是目前搜索引擎使用的一種關鍵技術
索引可以極大地提高數據的查詢速度
通過使用索引,可以在查詢的過程中,使用優化隱藏器,提高系統的性能
但是會降低插入、刪除、更新表的速度,因為在執行這些寫操作的時候,還要操作索引文件
索引需要占物理空間,除了數據表占數據空間之外,每一個索引還要占一定的物理空間,如果要簡歷聚簇索引,那么需要的空間就會更大,如果非聚簇索引很多,一旦聚簇索引改變,那么所有非聚簇索引都會跟著變
mysql聚簇和非聚簇索引的區別
都是B+樹的數據結構 聚簇索引:將數據存儲與索引放到了一塊、并且是按照一定的順序組織的,找到索引也就找到了數 據,數據的物理存放順序與索引順序是一致的,即:只要索引是相鄰的,那么對應的數據一定也是 相鄰地存放在磁盤上的 非聚簇索引:葉子節點不存儲數據、存儲的是數據行地址,也就是說根據索引查找到數據行的位置 再取磁盤查找數據,這個就有點類似一本樹的目錄,比如我們要找第三章第一節,那我們先在這個 目錄里面找,找到對應的頁碼后再去對應的頁碼看文章。