MySQL(十五)----- SQL語句優化

        通常在數據量較少的時候,我們並沒有那麼在意SQL語句的性能問題,只要能到達目的即可;但是當你面對浩大的數據量仍然這麼做時,面臨的往往是耗時良久或者數據崩潰;當然,數據庫優化的方式有很多,這裏我們着重介紹SQL優化。

準備工作:

          既然要研究數據量較大的表,那麼首先我們需要一個數據庫,該數據庫裏要有很多表,表中要有很多內容;MySQL官方提供了一個模擬電影出租廳信息管理系統的數據庫sakila,它的下載地址爲:http://downloads.mysql.com/docs/sakila-db.zip 。壓縮包中包含三個文件:

  • sakila-schema.sql:數據庫及表結構創建文本;
  • sakila-data.sql:數據插入文本;
  • sakila.mwb:sakila的MySQL Workbench數據模型,可以在MySQL工作臺打開查看該數據模型。

        打開cmd終端,連上MySQL數據庫,執行兩個腳本文件 :

        mysql> source C:\\Users\\15330\\Desktop\\sakila-schema.sql;

        mysql> source C:\\Users\\15330\\Desktop\\sakila-data.sql;

成功後數據就準備好了。

一、優化SQL語句的一般步驟

一般分爲四步:

1. 瞭解數據庫各種SQL語句執行的頻率,通過頻率初步得出可能存在的問題;

2. 定位到執行效率低的SQL語句上;

3. 通過多種方法分析導致低效SQL語句的原因; 

4. 根據找到的原因提出合理的解決辦法,達到優化的目的。

      下面就根據這些步驟一一進行介紹。

1.1 通過show status命令查看各語句的頻率

        可以在MySQL連接後使用命令 SHOW [session | global] STATUS命令查看,也可以在操作系統上使用 mysqladmin extended-status 命令來查看。session關鍵字用來顯示session級(當前連接)的統計結果,global關鍵字用來顯示global級(自數據庫上次啓動至今)的統計結果。省略不寫的話默認爲session。

例子:

mysql> show status like 'Com_%';
+-----------------------------+-------+
| Variable_name               | Value |
+-----------------------------+-------+
| Com_admin_commands          | 0     |
| Com_assign_to_keycache      | 0     |
| Com_alter_db                | 0     |
| Com_alter_db_upgrade        | 0     |
| Com_alter_event             | 0     |
| Com_alter_function          | 0     |
| Com_alter_instance          | 0     |
| Com_alter_procedure         | 0     |
| Com_alter_server            | 0     |
| Com_alter_table             | 2     |
。。。。。

       Com_xxx表示xxx語句執行的次數,通常有以下幾個比較關心:

  • Com_select:執行SELECT操作的次數,一次查詢只累加1;
  • Com_insert:執行INSERT操作的次數,一次插入只累加1,批量插入也只算一次;
  • Com_update:執行UPDATE操作的次數;
  • Com_delete:執行DELETE操作的次數;

    上面的參數對所有的存儲引擎都適用,下面幾個參數是單獨針對InnoDB的,累加的算法也略有不同:

  • Innodb_rows_read:SELECT查詢返回的行數;
  • Innodb_rows_inserted:INSERT操作插入的行數;
  • Innodb_rows_updated:UPDATA操作更新的行數;
  • Innodb_rows_deleted:DELETED操作刪除的行數;

        注意:上面的更新操作計數,是對執行次數的計數,因此不論是提交還是回滾都會進行累加。

        通過Com_commit 和 Com_rollback可以看到事務的提交和回滾情況,對於回滾非常頻繁的數據庫,可能就意味着應用編寫的有問題。

       通過這些參數我們就可以瞭解到當前數據庫的應用是以插入更新爲主還是查詢操作爲主,以及各種類型的SQL大致執行的比例是多少;這樣我們就可以根據這個大方向來判斷可能會有問題的SQL語句。

       以下幾個參數可以便於用戶瞭解數據庫的基本情況:

  • Connections:試圖連接MySQL服務器的次數;
  • Uptime:服務器工作時間;
  • Slow_queries:慢查詢的次數。

1.2 定位執行效率低的SQL語句

       可以通過以下兩種方式來定位執行效率低的SQL語句:

  • 通過慢查詢日誌定位;通過設定long_query_time的大小來指定SQL語句執行時間超過設定值時就記錄到慢查詢日誌中,然後通過查詢日誌就可以找到相應執行緩慢的SQL語句了;
  • 慢查詢日誌只是在查詢結束後才記錄,所以,如果要實時查看,慢查詢日誌是無法起作用的;這時可以使用show processlist命令查看當前MySQL在進行的線程,包括線程的狀態,是否鎖表等等,可以看到實時的狀態。

1.3 分析原因

 通過EXPLAIN分析

         可以通過 EXPLAIN 或 DESC 命令來獲取語句的執行信息,通過這些信息我們可以分析出一些問題,例如看下面的例子:

mysql> explain select sum(amount) from customer a,payment b where 1=1 and a.customer_id = b.customer_id and email = '[email protected]' \G;
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: a
   partitions: NULL
         type: ALL
possible_keys: PRIMARY
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 599
     filtered: 10.00
        Extra: Using where
*************************** 2. row ***************************
           id: 1
  select_type: SIMPLE
        table: b
   partitions: NULL
         type: ref
possible_keys: idx_fk_customer_id
          key: idx_fk_customer_id
      key_len: 2
          ref: sakila.a.customer_id
         rows: 26
     filtered: 100.00
        Extra: NULL
2 rows in set, 1 warning (0.01 sec)

下面解釋一下各個參數的意義,這樣通過參數的值就大概能清楚SQL語句執行過程中的問題:

  • id:select查詢的序列號,是一組數字,表示的是查詢中執行select子句或者是操作表的順序。id相同表示加載表的順序是從上到下;id不同id值越大,優先級越高,越先被執行;id有相同,也有不同,同時存在。id相同的可以認爲是一組,從上往下順序執行;在所有的組中,id的值越大,優先級越高,越先執行。
  • select_type:表示SELECT的類型,常見的取值有SIMPLE(簡單表,即不使用表連接或子查詢)、PRIMARY(主查詢,即外層的查詢)、UNION(UNION中的第二個或者後面的查詢語句)、SUBQUERY(子查詢中的第一個SELECT)等。
  • table:輸出結果集的表。
  • type:MySQL在表中找到所需行的方式,或者叫訪問類型;常見的取值有ALL、index、range、ref、eq_ref、const/system、NULL,性能從前到後依次變好。
  • possible_keys:表示查詢時可能使用的索引;
  • key:表示實際使用的索引;
  • key_len:使用到索引字段的長度,在不損失精度的情況下長度越短越好;
  • ref:顯示索引的哪一列被使用了;
  • rows:掃描行的數量;
  • filtered:過濾掉的行數;
  • Extra:執行情況的說明和描述,通常會包含一些比較重要的額外信息;

下面着重介紹以下type類型,從性能最差到最好一次介紹:

   1. type=ALL,全表掃描;

mysql> explain select * from film where rating > 9 \G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: film
   partitions: NULL
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 1000
     filtered: 33.33
        Extra: Using where
1 row in set, 1 warning (0.01 sec)

   2. type=index,全索引掃描;

mysql> explain select title from film \G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: film
   partitions: NULL
         type: index
possible_keys: NULL
          key: idx_title
      key_len: 767
          ref: NULL
         rows: 1000
     filtered: 100.00
        Extra: Using index
1 row in set, 1 warning (0.00 sec)

   3. type=range,索引範圍掃描;常見於< > <= >= between等操作符;

mysql> explain select * from payment where customer_id >=300 and customer_id <= 350\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: payment
   partitions: NULL
         type: range
possible_keys: idx_fk_customer_id
          key: idx_fk_customer_id
      key_len: 2
          ref: NULL
         rows: 1350
     filtered: 100.00
        Extra: Using index condition
1 row in set, 1 warning (0.00 sec)

   4. type=ref,使用非唯一索引掃描或唯一索引的前綴掃描,返回匹配某個單獨值的記錄行;

mysql> explain select * from payment where customer_id = 350\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: payment
   partitions: NULL
         type: ref
possible_keys: idx_fk_customer_id
          key: idx_fk_customer_id
      key_len: 2
          ref: const
         rows: 23
     filtered: 100.00
        Extra: NULL
1 row in set, 1 warning (0.00 sec)

   5. type=eq_ref,類似於ref,區別在於使用的索引是唯一索引,對於索引的鍵值,表中只有一條記錄匹配;簡單的來說就是多表連接中使用primary key或unique index作爲關聯條件。

mysql> explain select * from film a,film_text b where a.film_id = b.film_id\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: b
   partitions: NULL
         type: ALL
possible_keys: PRIMARY
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 1000
     filtered: 100.00
        Extra: NULL
*************************** 2. row ***************************
           id: 1
  select_type: SIMPLE
        table: a
   partitions: NULL
         type: eq_ref
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 2
          ref: sakila.b.film_id
         rows: 1
     filtered: 100.00
        Extra: Using where
2 rows in set, 1 warning (0.01 sec)

     6. type=const/system,單表中最多有一個匹配行,查詢起來非常迅速;這個匹配行中的其它列的值可以被優化器在當前查詢中當做常量來處理,例如根據主鍵和唯一鍵進行的查詢。

     7. type=NULL,不用訪問表或者索引,直接就可以得到結果;

     還有很多取值還沒列出,比如ref_or_null等等,後面遇到了再查會好一些。

     再提一句,以前老版本中還有EXPLAIN EXTENDED 命令、EXPLAIN PARTITIONS命令,現在MySQL5.1版本之後都統一在EXPLAIN命令中了。

      通過EXPLAIN命令分析例子中的SQL語句我們得知影響查詢速度的原因是進行了全表掃描,但有時候這個方法也並不能分析出本質的原因,下面再介紹一種profile聯合分析方法。

show profile分析方法:(注意5.6.7版本之後換成了新的命令performance schema)

         profile方法可以清楚的看到SQL語句在各個階段執行時所需要的時間。查看當前MySQL是否支持profile方法

mysql> select @@have_profiling;
+------------------+
| @@have_profiling |
+------------------+
| YES              |
+------------------+
1 row in set, 1 warning (0.00 sec)

         默認profiling是關閉的,可以通過set在session級別開啓profiling,開啓後只保存最近15次的運行結果:

mysql> select @@profiling;
+-------------+
| @@profiling |
+-------------+
|           0 |
+-------------+
1 row in set, 1 warning (0.00 sec)

mysql> set profiling=1;
Query OK, 0 rows affected, 1 warning (0.00 sec)

          舉個例子,同樣是COUNT(*)操作,對於InnoDB類型的表,因爲沒有元數據緩存因此執行的較慢;但對於MyISAM類型的表,因爲有表元數據的緩存,因此執行的較快。下面通過profile來具體分析一下:

mysql> select count(*) from payment;
+----------+
| count(*) |
+----------+
|    16049 |
+----------+
1 row in set (0.01 sec)

mysql> show profiles;
+----------+------------+------------------------------+
| Query_ID | Duration   | Query                        |
+----------+------------+------------------------------+
|        1 | 0.01137100 | select count(*) from payment |
+----------+------------+------------------------------+
1 row in set, 1 warning (0.00 sec)

mysql> show profile for query 1;
+----------------------+----------+
| Status               | Duration |
+----------------------+----------+
| starting             | 0.000058 |
| checking permissions | 0.000006 |
| Opening tables       | 0.000015 |
| init                 | 0.000016 |
| System lock          | 0.000007 |
| optimizing           | 0.011142 |
| executing            | 0.000016 |
| end                  | 0.000002 |
| query end            | 0.000009 |
| closing tables       | 0.000008 |
| freeing items        | 0.000047 |
| cleaning up          | 0.000045 |
+----------------------+----------+
12 rows in set, 1 warning (0.00 sec)

mysql> create table payment_myisam like payment;
Query OK, 0 rows affected (0.04 sec)

mysql> alter table payment_myisam engine=myisam;
Query OK, 0 rows affected (0.04 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> insert into payment_myisam select * from payment;
Query OK, 16049 rows affected (0.06 sec)
Records: 16049  Duplicates: 0  Warnings: 0

mysql> select count(*) from payment_myisam;
+----------+
| count(*) |
+----------+
|    16049 |
+----------+
1 row in set (0.00 sec)

mysql> show profiles;
+----------+------------+--------------------------------------------------+
| Query_ID | Duration   | Query                                            |
+----------+------------+--------------------------------------------------+
|        1 | 0.01137100 | select count(*) from payment                     |
|        2 | 0.00022550 | show wainings                                    |
|        3 | 0.00011500 | show warnings                                    |
|        4 | 0.00015000 | show warnings                                    |
|        5 | 0.00012900 | performance schema                               |
|        6 | 0.03744450 | create table payment_myisam like payment         |
|        7 | 0.03600900 | alter table payment_myisam engine=myisam         |
|        8 | 0.06122275 | insert into payment_myisam select * from payment |
|        9 | 0.00016400 | select count(*) from payment_myisam              |
+----------+------------+--------------------------------------------------+
9 rows in set, 1 warning (0.00 sec)

mysql> show profile for query 9;
+----------------------+----------+
| Status               | Duration |
+----------------------+----------+
| starting             | 0.000047 |
| checking permissions | 0.000004 |
| Opening tables       | 0.000013 |
| init                 | 0.000020 |
| System lock          | 0.000005 |
| optimizing           | 0.000006 |
| executing            | 0.000006 |
| end                  | 0.000003 |
| query end            | 0.000004 |
| closing tables       | 0.000008 |
| freeing items        | 0.000032 |
| cleaning up          | 0.000016 |
+----------------------+----------+
12 rows in set, 1 warning (0.00 sec)

       從例子中可以看到,InnoDB類型的表在optimizing過程中消耗了非常多的時間,而MyISAM類型的表基本沒有消耗太多時間。

       我們還可以用一個或多個關鍵字來查看optimizing消耗的那麼多時間主要浪費在了什麼資源上:

  • ALL: 顯示所有的開銷信息;

  • BLOCK IO : 顯示塊IO相關開銷;

  • CONTEXT SWITCHS: 上下文切換相關開銷;

  • CPU : 顯示cpu 相關開銷;

  • IPC: 顯示發送和接收相關開銷;

  • MEMORY: 顯示內存相關開銷;

  • PAGE FAULTS:顯示頁面錯誤相關開銷信息;

  • SOURCE : 顯示和Source_function ,Source_file,Source_line 相關的開銷信息;

  • SWAPS:顯示交換次數相關的開銷信息;

比如要查看在CPU上消耗的時間:可以看到optimizing的時間主要消耗自系統cpu上;

mysql> show profile cpu for query 1;
+----------------------+----------+----------+------------+
| Status               | Duration | CPU_user | CPU_system |
+----------------------+----------+----------+------------+
| starting             | 0.000058 | 0.000000 |   0.000000 |
| checking permissions | 0.000006 | 0.000000 |   0.000000 |
| Opening tables       | 0.000015 | 0.000000 |   0.000000 |
| init                 | 0.000016 | 0.000000 |   0.000000 |
| System lock          | 0.000007 | 0.000000 |   0.000000 |
| optimizing           | 0.011142 | 0.000000 |   0.015625 |
| executing            | 0.000016 | 0.000000 |   0.000000 |
| end                  | 0.000002 | 0.000000 |   0.000000 |
| query end            | 0.000009 | 0.000000 |   0.000000 |
| closing tables       | 0.000008 | 0.000000 |   0.000000 |
| freeing items        | 0.000047 | 0.000000 |   0.000000 |
| cleaning up          | 0.000045 | 0.000000 |   0.000000 |
+----------------------+----------+----------+------------+
12 rows in set, 1 warning (0.00 sec)

            如果對源碼感興趣,還可以使用 show profile source for query查看源碼文件的相關信息。

通過trace分析:

        MySQL5.6提供了對SQL的跟蹤trace,通過trace文件可以進一步瞭解爲什麼優化器爲什麼選擇A執行計劃而不選擇B執行計劃,這樣可以幫助我們更好的理解優化器的行爲。

       使用方式:首先打開trace,設置格式爲JSON,並設置最大能夠使用的內存大小,避免解析過程中內存太小而不能完整顯示;然後執行想要做trace的SQL語句;最後檢查INFORMATION_SCHEMA.OPTIMIZER_TRACE 就可以知道MySQL是如何執行SQL語句的。

mysql> set optimizer_trace="enabled=on",end_markers_in_json=on;
Query OK, 0 rows affected (0.00 sec)

mysql> set optimizer_trace_max_mem_size=1000000;
Query OK, 0 rows affected (0.00 sec)

mysql> select rental_id from rental where 1=1 and rental_date >= '2005-05-25 04:00:00' and rental_date <= '2005-05-25 05:00:00' and inventory_id=4466;
+-----------+
| rental_id |
+-----------+
|        39 |
+-----------+
1 row in set (0.01 sec)

mysql> select * from information_schema.optimizer_trace \G
*************************** 1. row ***************************
                            QUERY: select rental_id from rental where 1=1 and rental_date >= '2005-05-25 04:00:00' and rental_date <= '2005-05-25 05:00:00' and inventory_id=4466
                            TRACE: {
  "steps": [
    {
      "join_preparation": {
        "select#": 1,
        "steps": [
          {
            "expanded_query": "/* select#1 */ select `rental`.`rental_id` AS `rental_id` from `rental` where ((1 = 1) and (`rental`.`rental_date` >= '2005-05-25 04:00:00') and (`rental`.`rental_date` <= '2005-05-25 05:00:00') and (`rental`.`inventory_id` = 4466))"
          }
        ] /* steps */
。。。。。完整文件就不貼出來了,太長了

1.4 確定問題並採取相應辦法

         經過以上步驟大致就可以確定出現問題的原因,現在就是對應原因做出優化。比如前面提到過的那個因爲是全表掃描導致查詢結果緩慢的SQL語句,根據這一點,我們可以對它創建索引來提高查詢效率:

mysql> create index idx_email on customer(email);
Query OK, 0 rows affected (0.04 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> explain select sum(amount) from customer a,payment b where 1=1 and a.customer_id = b.customer_id and email = '[email protected]' \G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: a
   partitions: NULL
         type: ref
possible_keys: PRIMARY,idx_email
          key: idx_email
      key_len: 153
          ref: const
         rows: 1
     filtered: 100.00
        Extra: Using index
*************************** 2. row ***************************
           id: 1
  select_type: SIMPLE
        table: b
   partitions: NULL
         type: ref
possible_keys: idx_fk_customer_id
          key: idx_fk_customer_id
      key_len: 2
          ref: sakila.a.customer_id
         rows: 26
     filtered: 100.00
        Extra: NULL
2 rows in set, 1 warning (0.00 sec)

           可以看到對customer表的email建立索引過後,查詢耗費的時間明顯減少,並且查詢的行數從583行減到1行,這說明建立索引可以十分精確的查找到所需內容,但有一點需要注意,它的key_len明顯增大了。

二、兩個簡單實用的優化方法

       優化的方法有很多,但是對於一般開發人員來說下面介紹的兩個最簡單實用,一般掌握這兩個就很有用處了。

2.1 定期分析表和檢查表

       分析表的語法如下:

        ANALYZE [LOCAL | NO_WRITE_TO_BINLOG] TABLE tbl_name [,  tbl_name ] ....

       這條語句能夠用於分析然後存儲表的關鍵字分佈,分析的結果可以使得系統得到準確的統計信息,使得SQL能夠生成正確的執行計劃。比如當某個執行某個計劃時並不是預期的那樣而又不知道原因時,執行一次分析表可能會解決問題。

例如對錶payment進行分析
mysql> analyze table payment;
+----------------+---------+----------+----------+
| Table          | Op      | Msg_type | Msg_text |
+----------------+---------+----------+----------+
| sakila.payment | analyze | status   | OK       |
+----------------+---------+----------+----------+
1 row in set (0.02 sec)

          檢查表的語法如下:

          CHECK TABLE tbl_name [, tbl_name] ...[option] ... option = {QUICK|FAST|MEDIUM|EXTENDED|CHANGED}

          檢查表的作用是檢查一個或多個表是否有錯誤,check table語句對MyISAM和InnoDB表有作用;並且對MyISAM表來說,關鍵字統計數據會被更新,例如

mysql> check table payment_myisam;
+-----------------------+-------+----------+----------+
| Table                 | Op    | Msg_type | Msg_text |
+-----------------------+-------+----------+----------+
| sakila.payment_myisam | check | status   | OK       |
+-----------------------+-------+----------+----------+
1 row in set (0.01 sec)

           檢查表語句也可以檢查視圖是否有錯誤,比如視圖定義中的表已經不存在,舉例如下:

1. 首先創建一個視圖,依賴表payment_myisam
mysql> create view v_payment_myisam as select * from payment_myisam;
Query OK, 0 rows affected (0.01 sec)

2. 檢查一下視圖,發現並沒有問題
mysql> check table v_payment_myisam;
+-------------------------+-------+----------+----------+
| Table                   | Op    | Msg_type | Msg_text |
+-------------------------+-------+----------+----------+
| sakila.v_payment_myisam | check | status   | OK       |
+-------------------------+-------+----------+----------+
1 row in set (0.00 sec)

3. 刪除視圖依賴的表payment_myisam
mysql> drop table payment_myisam;
Query OK, 0 rows affected (0.00 sec)

4. 再檢查視圖發現出錯了
mysql> check table v_payment_myisam \G
*************************** 1. row ***************************
   Table: sakila.v_payment_myisam
      Op: check
Msg_type: Error
Msg_text: Table 'sakila.payment_myisam' doesn't exist
*************************** 2. row ***************************
   Table: sakila.v_payment_myisam
      Op: check
Msg_type: Error
Msg_text: View 'sakila.v_payment_myisam' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
*************************** 3. row ***************************
   Table: sakila.v_payment_myisam
      Op: check
Msg_type: error
Msg_text: Corrupt
3 rows in set (0.00 sec)

2.2 定期優化表

       優化表的語法如下:

       OPTIMIZE [LOCAL | NO_WRITE_TO_BINLOG] TABLE tbl_name [, tbl_name] ...

       如果已經刪除了表的一大部分,或者如果已經對含有可變長度行的表(含有varchar、blob、text列的表)進行了很多更改,那麼應該使用OPTIMIZE TABLE語句來進行表優化。(前面第五節講blob和text字符類型時有提到過)這個命令可以將表中的空間碎片進行合併,並且可以消除由於刪除或者更新造成的的空間浪費,但這個命令只對MyISAM、BDB、InnoDB表起作用。

       比如下面的例子優化表payment_myisam,由於這個表已經被刪掉了,所以會出現如下情況:

mysql> optimize table payment_myisam;
+-----------------------+----------+----------+---------------------------------------------+
| Table                 | Op       | Msg_type | Msg_text                                    |
+-----------------------+----------+----------+---------------------------------------------+
| sakila.payment_myisam | optimize | Error    | Table 'sakila.payment_myisam' doesn't exist |
| sakila.payment_myisam | optimize | status   | Operation failed                            |
+-----------------------+----------+----------+---------------------------------------------+
2 rows in set (0.00 sec)

         對於InnoDB引擎的表來說,通過設置innodb_file_per_table參數,將InnoDB設置爲獨立表空間模式,這樣,每個數據庫的每個表都會生成一個獨立的ibd文件,用於存儲表的數據和索引,這樣做在一定程度上可以減輕InnoDB表空間回收的問題。另外,在刪除大量數據後,InnoDB表可以通過alter table但是不修改引擎的方式來回收不用的空間:

mysql> alter table payment engine=innodb;
Query OK, 0 rows affected (0.43 sec)
Records: 0  Duplicates: 0  Warnings: 0

        注意:ANALYZE、CHECK、OPTIMIZE、ALTER TABLE執行期間將對錶進行鎖定,因此一定注意要在數據庫不繁忙的時候執行相關操作。

三、常用的SQL的優化

         最常用的是通過索引來優化查詢,這一個會單獨拿出來說;其它的語句像插入、分組等待都有各自的優化方法,下面就一一進行介紹。

3.1 大批量插入數據

      未完待續。。。

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章