數據庫查詢優化的12種方式


查詢優化方式:

 

 

1 硬件層的優化

1 CPU:
個數 / 核數 / 頻率 / 線程數 / 一級 cache/ 二級 cache
2 內存 :
容量與 64-bits/ 帶寬
3 I/O:
seek(>100 次 / 秒 )/read/write(>10–20MB/s)
4 網絡 :
帶寬 / 傳輸協議

2 存儲引擎優化

1 InnoDB :
1) innodb_buffer_pool_size : caching data and indexes in memory ,可配置為
可用內存的(非物理內存)的 50%--60%
2) innodb_buffer_pool_instances :配合 innodb_buffer_pool_size 使用,把 buf
分區,增加並發度
2 MyISAM :
1) key_buffer_size : Index blocks for MyISAM tables are buffered and are shared
by all threads ,可配置為可用內存的 10-%-20%
2) table_open_cache : The number of open tables for all threads. 使用“ SHOW
GLOBAL STATUS LIKE 'Opened_tables';” 命令檢查“ Opened_tables” 的值,太
小則改大

秘訣:
磁盤類數據庫,瓶頸在 IO ;
必須優先調整和 IO 有關的參數。
解決 IO 瓶頸的方法,就是緩存;
必須優先調整和緩存相關的參數。

3 表設計優化

1 表的存儲引擎選擇:事務型選 InnoDB ,非事務型選 MyISAM 等
2 表的壓縮選擇:壓縮的表 IO 少, CPU 空閑 IO 瓶頸大課采取壓縮
3 表結構符合第三范式:更新類應用可讓表的個數多些單表的列少一些;分析類的應用可讓
表個數少些單表的列多些
4 表數據物理分布策略:盡量讓表的數據分散在不同的物理存儲設備上。利用表空間技術把
數據分散
5 表數據邏輯分布策略:利用分區技術把數據從邏輯上即分開
6 表的數據類型選擇:數字類型優於字符類型;長度小的優於長度大的。變長的 VARCHAR
優於定長的 CHAR 。 BLOB 類型用 BINARY VARCHAR 替代,替代不了則用單獨的表存放。
如果比較 BLOB 類,則新建字段其值等於用 MD5() 處理后的結果。 BOLB 類型甚至不存放到
數據庫內部,數據庫只存儲 BLOB 的路徑。
7 啟用完整性約束:使用 NOT NULL 標識字段 ; 設置 default value 。
8 其他:列名不超過 18 個字符。使用 sample character set (如用 latin1 ,盡量少用 utf-8
等,因為 utf-8 等占用的空間是 latin1 的 3 倍)

4 InnoDB 優化

1 單表容量優化: OPTIMIZE TABLE statement to reorganize the table and
compact any wasted space 。
2 單表統計數據優化: ANALYZE TABLE tpch.customer;
3 啟用壓縮:測試各級壓縮哪種有效
4 應用盡量使用短事務減少使用長事務:應用程序控制
5 事務管理:
5.1 寫操作多: SET AUTOCOMMIT=0 or a START TRANSACTION statement,
followed by a COMMIT statement after making all the changes.
5.2 讀操作多: SET AUTOCOMMIT=1
6 加大日志文件和日志緩存: innodb_log_buffer_size + innodb_log_file_size

7 主鍵建立:使用最重要且是最常用的列作主鍵,務必建立主鍵而不是使用
InnoDB 默認方式
8 主鍵列的數據類型不要太長:浪費存儲空間和內存,浪費其他索引的空間和內存
9 有效建立索引:除主鍵外,盡量建立聯合索引而不是多個單列上分別建立
secondary index
10 刪除數據釋放空間: Use TRUNCATE TABLE to empty a table, not DELETE
FROM tbl_name.
11 數據刷出的方式: In some versions of GNU/Linux and Unix, flushing files to
disk with the Unix fsync() call (which InnoDB uses by default) and similar methods
is surprisingly slow. If database write performance is an issue, conduct
benchmarks with the innodb_flush_method parameter set to O_DSYNC.
其他刷出方式參考: optimization.html#optimizing-innodb-storage-layout

5 庫級優化

5.1 同一個庫中表不要太多:設置 table_open_cache 和 max_connections 來調整。
With MyISAM tables, one extra file descriptor is required for the data file for each client that has the table open. (By contrast, the index file descriptor is shared
between all sessions.)

5.2 啟用查詢緩存: 適用於特定場景 .
If you often have recurring queries for tables that are not updated frequently, enable the query cache:
[mysqld]
query_cache_type = 1
query_cache_size = 10M

5.3 使用長連接: 避免頻繁使用短連接 .
推薦啟用連接池 .
設置 thread_cache_size : 8 + (max_connections / 100) <--default value This variable can be increased to improve performance if you have a lot of new
connections. Normally, this does not provide a notable performance improvement if you have a good thread implementation. However, if your server sees hundreds of connections per second you should normally set thread_cache_size high enough so that most new connections use cached threads.

5.4 主從架構: 復制技術, master 完成寫操作, slave 完成讀操作 .
1) 優化讀寫操作
2) 提高備份速度,減少對 master 的影響

6 數據獲取方式的優化

1 一次獲取的數據盡量少:查詢獲取數據 , 盡量帶 WHERE 條件精確指定獲取范
圍 , 且一次獲取的數據量要少(應用層開發階段必須注意)
數據獲取,遵循的基本原則:
--- 少:不要全表掃描。要用什么取什么
--- 准:帶 where 條件獲取,用誰取誰
--- 快:加索引到 where 條件涉及的列上,用誰則快速取到誰
--- 減少關聯:沒有直接聯系,不要硬拉郎配。減少耦合,減少關聯。

2 不用 select * : 臭名昭著,遠遠避之。
獲取什么列就明確指定列名。
查詢語句中出現的列名,最好是索引的一部分。
3 LIMIT x :在滿足應用需求的情況下可限制元組個數

7 利用索引優化

1 正確使用索引:

每條查詢,使用 EXPLAIN 驗證2 索引列做條件不參與運算: index_col <op> expression如 : col IN (value1, value2,...), col 是索引列,才可以利用索引加快數據
獲取速度 . 操作符一側的對象必須是不參與運算的索引列 .
3 精確化查找條件:單表不做全部數據讀取,多表連接不做全表掃描,務必
帶有 WHERE 子句限制數據, WHERE 子句中列對象有合適的索引可用
4 等式 / 不等式的一些推理人工完成:
a>b AND b>3 ==> a>3 AND b>3 AND a>b
a 列上有索引且選擇率低
5 求最值建索引:

單表求 MIN/MAX/COUNT(*) 的操作,最好在對應列上建立索引

6 GROUPBY 、 ORDERBY 、 DISTINCT 作用在索引列上:
6.1 利用索引進行 GROUPBY 、 ORDERBY 、 DISTINCT 操作(考慮在這些謂詞
后面的對象上建立索引)
6.2 避免使用隨機數等不確定的對象做排序分組操作,如不用: ORDER BY RAN
D()
7 建立主外鍵關系:盡管 MySQL 目前不支持帶有主外鍵關系的表連接優

(好處:符合第三范式,表明實體已經被拆分為小表,有利於減少讀取的數據量)

8 引入新列:在表上增加新列,並在其上創建索引
SELECT * FROM tbl_name
WHERE hash_col=MD5(CONCAT(col1,col2))
AND col1='constant' AND col2='constant';
BLOB 的比較,也可以使用同樣的方式。
9 存在范圍查找,建立 Btree 索引:默認情況下是 Btree 。
10 索引類型:盡量使用主鍵索引 / 唯一索引。

11 創建索引 : 索引的鍵值類型越短越好。在數值型列上創建索引最好。
12 少建索引:對 InnoDB ,主鍵不可用時,盡量用聯合索引替換多個單
列的 second index 。
13 刪除索引:刪除使用很少的索引。
14 只讀索引: Covering Indexes ,覆蓋索引。 查詢語句中出現的對象
盡量限制在單個索引的全部列中。
15 前綴索引:盡量使用索引的前綴部分。
16 通配符:字符型索引列參與比較,另外各一個操作符前不用通配符。
key LIKE ‘%abc’

17 強制索引:特定情況強制使用指定的索引
index_hint:
USE {INDEX|KEY}
[FOR {JOIN|ORDER BY|GROUP BY}] ([index_list])
| IGNORE {INDEX|KEY}
[FOR {JOIN|ORDER BY|GROUP BY}] (index_list)
| FORCE {INDEX|KEY}
[FOR {JOIN|ORDER BY|GROUP BY}] (index_list)
示例:
http://blog.163.com/li_hx/blog/static/183991413201461853637715/

18 索引誤區:
1) 不使用 NOT IN 和 <> 操作
NOT IN 和 <> 操作都不會使用索引將進行全表掃描。
mysql> explain extended select key1 from tk1 where key1 <> 2;
+----+-------------+-------+-------+---------------+--------+---------+------+------+----------
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra
|
+----+-------------+-------+-------+---------------+--------+---------+------+------+----------
| 1 | SIMPLE | tk1 | range | tk1_i1 | tk1_i1 | 5 | NULL | 1000 | 100.00 | Using where;
Using index |
+----+-------------+-------+-------+---------------+--------+---------+------+------+----------
1 row in set, 1 warning (0.00 sec)
mysql> explain extended select * from tk1 where key1 <> 2;
+----+-------------+-------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+----------+-------------+
| 1 | SIMPLE | tk1 | ALL | tk1_i1 | NULL | NULL | NULL | 1001 | 99.90 | Using where |
+----+-------------+-------+------+---------------+------+----

 

2) 索引不會包含有 NULL 值的列
復合索引中只要有一列含有 NULL 值,那么這一列對於此復合索引就是無效的。所
以我們在數據庫設計時不要讓字段的默認值為 NULL 。
mysql> explain extended select key_part2 from tk1 where key_part2=2;
+----+-------------+-------+-------+---------------+----------+---------+------+------+----------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+-------+---------------+----------+---------+------+------+----------+--------------------------+
| 1 | SIMPLE | tk1 | index | NULL | tk1_i123 | 15 | NULL | 1000 | 100.00 | Using where; Using index |
+----+-------------+-------+-------+---------------+----------+---------+------+------+----------+--------------------------+
1 row in set, 1 warning (0.00 sec)
mysql> insert into tk1 values(5000, 5000,5000,5000, NULL,5000,5000);
Query OK, 1 row affected (0.04 sec)
mysql> explain extended select key_part2 from tk1 where key_part2=2;
+----+-------------+-------+-------+---------------+----------+---------+------+------+----------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+-------+---------------+----------+---------+------+------+----------+--------------------------+
| 1 | SIMPLE | tk1 | index | NULL | tk1_i123 | 15 | NULL | 1001 | 100.00 | Using where; Using index |
+----+-------------+-------+-------+---------------+----------+---------+------+------+----------+--------------------------+
1 row in set, 1 warning (0.00 sec)

8 暫存中間結果的三種優化方式

1 利用物化視圖臨時儲存確定的查詢結果 / 統計結果:
create algorithm=temptable view my_view as
select * from t1, t2;
select a, b from my_view where ...;
2 或者把結果永久儲存到特定的表中 :
create table my_result select * from t1, t2;
3 或者把結果暫時存在臨時表中 :
sql_buffer_result : If set to 1, sql_buffer_result forces results from SELECT stat ements to be put into temporary tables. This helps MySQL free the table locks earl y and can be beneficial in cases where it takes a long time to send results to the client.

9 控制查詢優化器

SET [GLOBAL|SESSION] optimizer_switch='command[,command]...';
batched_key_access={on|off}
block_nested_loop={on|off}
engine_condition_pushdown={on|off}
firstmatch={on|off}
index_condition_pushdown={on|off}
index_merge={on|off}
index_merge_intersection={on|off}
index_merge_sort_union={on|off}
index_merge_union={on|off}
loosescan={on|off}
materialization={on|off}
mrr={on|off}
mrr_cost_based={on|off}
semijoin={on|off}
subquery_materialization_cost_based={on|off}
use_index_extensions={on|off}

10 重新組織數據

1 物理數據分布 -- 重新組織表數據:
方法 1 : OPTIMIZE TABLE
方法 2 :特定表,常使用 'expr1, expr2’ 排序,則‘ ALTER TABLE ... ORDER BY
expr1, expr2’
2 查詢優化邏輯使用的統計數據 -- 分析表數據 :
ANALYZE TABLE
3 查詢優化邏輯使用的統計數據 -- 調整系統參數:
innodb_stats_transient_sample_pages : The number of index pages to sample when estimating cardinality and other statistics for an indexed column, such as those calculated by ANALYZE TABLE. If your database has many large tables,consider using a higher value for innodb_stats_transient_sample_pages than if you have mostly smaller tables

11 連接技術

1 避免子查詢:使用子查詢上拉技術,人工優化子查詢。
WHERE 子句中的 IN/ALL/ANY/SOME 子查詢可以交給優化器優化
2 慎用不同的連接語義:慎用各種外連接、嵌套連接
3 明確連接條件 :
ON 子句指名連接列 , 盡量在主鍵和唯一鍵上做等值連接
WHERE 子句盡量利用索引中的主鍵索引和唯一索引
4 控制表的連接個數 :
7 表連接 , 可交給優化器處理
7 表以上的連接 , 考慮連接的必要性和連接條件

12 其他

1 使用語義優化技術:熟悉表結構和應用需求,利用語義優化技術書寫
查詢語句(設計階段就需要開始考慮)
2 使用 hint: 強迫優化器變更行為(優化器不是萬能的,多數時候可信)
3 查詢語句中慎用函數:特別檢察查詢語句中是否使用了函數,尤其是
值不穩定的函數(對於每行元組,值總在變化),盡量不用


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM