 # 1. 元數據 ## 1.1. metadata ## 1.2. 關於數據的數據 ## 1.3. 數據字典 ## ...
1. 元數據
1.1. metadata
1.2. 關於數據的數據
1.3. 數據字典
1.3.1. ⒅與外鍵關聯的數據表/列
1.3.2. ⒄外鍵列
1.3.3. ⒃外鍵名
1.3.4. ⒂存儲索引的信息
1.3.5. ⒁索引列的排序(升序或降序)
1.3.6. ⒀已索引的列
1.3.7. ⑿索引類型(B樹、點陣圖)
1.3.8. ⑾索引名
1.3.9. ⑩主鍵索引名
1.3.10. ⑨主鍵名
1.3.11. ⑧主鍵列
1.3.12. ⑦not null列約束
1.3.13. ⑥列名
1.3.14. ⑤列數據類型
1.3.15. ④列的預設值
1.3.16. ③存儲引擎
1.3.17. ②存儲數據表的信息(數據表空間、初始大小等)
1.3.18. ①數據表名
1.3.19. 系統編目
1.3.19.1. system catalog
2. information_schema資料庫
2.1. 所有可用對象都是視圖
2.2. information_schema的特殊模式,在每個資料庫中自動提供
2.3. 為了遵循ANSI SQL:2003標準,MySQL 和SQL Server都提供這個介面
2.4. information_schema資料庫中的視圖是可以被查詢的
2.5. information_schema.tables
2.5.1. mysql
-> SELECT table_name, table_type
-> FROM information_schema.tables
-> WHERE table_schema = 'sakila'
-> ORDER BY 1;
2.5.2. 包含了數據表和視圖
2.6. information_schema.views
2.6.1. mysql
-> SELECT table_name, is_updatable
-> FROM information_schema.views
-> WHERE table_schema = 'sakila'
-> ORDER BY 1;
2.7. information_schema.columns
2.7.1. mysql
-> SELECT column_name, data_type,
-> character_maximum_length char_max_len,
-> numeric_precision num_prcsn, numeric_scale num_scale
-> FROM information_schema.columns
-> WHERE table_schema = 'sakila' AND table_name = 'film'
-> ORDER BY ordinal_position;
2.8. information_schema.statistics
2.8.1. mysql
-> SELECT index_name, non_unique, seq_in_index, column_name
-> FROM information_schema.statistics
-> WHERE table_schema = 'sakila' AND table_name = 'rental'
-> ORDER BY 1, 3;
2.8.2. 檢索關於數據表的索引信息
2.9. information_schema.table_constraints
2.9.1. mysql
-> SELECT constraint_name, table_name, constraint_type
-> FROM information_schema.table_constraints
-> WHERE table_schema = 'sakila'
-> ORDER BY 3,1;
2.9.2. 檢索已創建的不同類型的約束(外鍵、主鍵、唯一)
3. 使用元數據
3.1. 模式生成腳本
3.1.1. mysql
-> SELECT 'CREATE TABLE category (' create_table_statement
-> UNION ALL
-> SELECT cols.txt
-> FROM
-> (SELECT concat(' ',column_name, ' ', column_type,
-> CASE
-> WHEN is_nullable = 'NO' THEN ' not null'
-> ELSE ''
-> END,
-> CASE
-> WHEN extra IS NOT NULL AND extra LIKE 'DEFAULT_GENERATED%'
-> THEN concat(' DEFAULT ',column_default,substr(extra,18))
-> WHEN extra IS NOT NULL THEN concat(' ', extra)
-> ELSE ''
-> END,
-> ',') txt
-> FROM information_schema.columns
-> WHERE table_schema = 'sakila' AND table_name = 'category'
-> ORDER BY ordinal_position
-> ) cols
-> UNION ALL
-> SELECT concat(' constraint primary key (')
-> FROM information_schema.table_constraints
-> WHERE table_schema = 'sakila' AND table_name = 'category'
-> AND constraint_type = 'PRIMARY KEY'
-> UNION ALL
-> SELECT cols.txt
-> FROM
-> (SELECT concat(CASE WHEN ordinal_position > 1 THEN ' ,'
-> ELSE ' ' END, column_name) txt
-> FROM information_schema.key_column_usage
-> WHERE table_schema = 'sakila' AND table_name = 'category'
-> AND constraint_name = 'PRIMARY'
-> ORDER BY ordinal_position
-> ) cols
-> UNION ALL
-> SELECT ' )'
-> UNION ALL
-> SELECT ')';
3.1.2. mysql
-> CREATE TABLE category2 (
-> category_id tinyint(3) unsigned not null auto_increment,
-> name varchar(25) not null ,
-> last_update timestamp not null DEFAULT CURRENT_TIMESTAMP
-> on update CURRENT_TIMESTAMP,
-> constraint primary key (
-> category_id
-> )
-> );
3.2. 驗證部署
3.2.1. 查詢返回Sakila模式中每個數據表的列數、索引數以及主鍵約束(0或1)數
3.2.2. mysql
-> SELECT tbl.table_name,
-> (SELECT count(*) FROM information_schema.columns clm
-> WHERE clm.table_schema = tbl.table_schema
-> AND clm.table_name = tbl.table_name) num_columns,
-> (SELECT count(*) FROM information_schema.statistics sta
-> WHERE sta.table_schema = tbl.table_schema
-> AND sta.table_name = tbl.table_name) num_indexes,
-> (SELECT count(*) FROM information_schema.table_constraints tc
-> WHERE tc.table_schema = tbl.table_schema
-> AND tc.table_name = tbl.table_name
-> AND tc.constraint_type = 'PRIMARY KEY') num_primary_keys
-> FROM information_schema.tables tbl
-> WHERE tbl.table_schema = 'sakila' AND tbl.table_type = 'BASE TABLE'
-> ORDER BY 1;
3.3. 動態SQL生成
3.3.1. mysql
-> SELECT concat('SELECT ',
-> concat_ws(',', cols.col1, cols.col2, cols.col3, cols.col4,
-> cols.col5, cols.col6, cols.col7, cols.col8, cols.col9),
-> ' FROM customer WHERE customer_id = ?')
-> INTO @qry
-> FROM
-> (SELECT
-> max(CASE WHEN ordinal_position = 1 THEN column_name
-> ELSE NULL END) col1,
-> max(CASE WHEN ordinal_position = 2 THEN column_name
-> ELSE NULL END) col2,
-> max(CASE WHEN ordinal_position = 3 THEN column_name
-> ELSE NULL END) col3,
-> max(CASE WHEN ordinal_position = 4 THEN column_name
-> ELSE NULL END) col4,
-> max(CASE WHEN ordinal_position = 5 THEN column_name
-> ELSE NULL END) col5,
-> max(CASE WHEN ordinal_position = 6 THEN column_name
-> ELSE NULL END) col6,
-> max(CASE WHEN ordinal_position = 7 THEN column_name
-> ELSE NULL END) col7,
-> max(CASE WHEN ordinal_position = 8 THEN column_name
-> ELSE NULL END) col8,
-> max(CASE WHEN ordinal_position = 9 THEN column_name
-> ELSE NULL END) col9
-> FROM information_schema.columns
-> WHERE table_schema = 'sakila' AND table_name = 'customer'
-> GROUP BY table_name
-> ) cols;
Query OK, 1 row affected (0.00 sec)
mysql> SELECT @qry;
+--------------------------------------------------------------------+
| @qry |
+--------------------------------------------------------------------+
| SELECT customer_id,store_id,first_name,last_name,email,
address_id,active,create_date,last_update
FROM customer WHERE customer_id = ? |
+--------------------------------------------------------------------+
1 row in set (0.00 sec)
mysql> PREPARE dynsql3 FROM @qry;
Query OK, 0 rows affected (0.00 sec)
Statement prepared
mysql> SET @custid = 45;
Query OK, 0 rows affected (0.00 sec)
mysql> EXECUTE dynsql3 USING @custid;
3.3.2. 使用包含迴圈結構的過程化語言(比如Java、PL/SQL、Transact-SQL或MySQL的存儲過程語言)生成查詢的做法更佳
4. 大型資料庫
4.1. 現代磁碟陣列可以存儲超過4PB的數據
4.2. 雲端存儲量基本上是無限的
4.2.1. 將服務托管在雲端所帶來的最大好處之一是即時可擴展性,允許快速提高或降低運行服務所需的計算能力
4.3. 通過分區、集群、分片等策略,企業可以通過將數據分散在多個存儲層和伺服器上來繼續使用關係型資料庫
4.4. 在視圖中,用戶與作為介面而不是實際數據表的模式對象進行交互
5. 分區
5.1. 數據表分區最初是在20世紀90年代後期由Oracle引入的
5.2. 當數據表增長至超過數百萬行時,會變得愈加困難和/或耗時的任務
5.2.1. 需要全表掃描的查詢
5.2.2. 索引創建/重建
5.2.3. 數據歸檔/刪除
5.2.4. 生成數據表/統計索引信息
5.2.5. 數據表重定位(例如,移動到不同的表空間)
5.2.6. 資料庫備份
5.3. 數據表被分區後,會創建出兩個或更多的數據表分區
5.4. 每個分區的定義完全相同,但具有不重疊的數據子集
5.5. 一旦數據表被分區,數據表本身就變成了一個虛擬的概念
5.6. 分區保存數據,任何索引都建立在分區數據之上
5.7. 優勢
5.7.1. 只需要與一個分區交互,而不再與整個數據表交互
5.7.2. 分區修剪(partition pruning)
5.7.2.1. 伺服器會檢查數據表的元數據,以確定實際需要包含哪些分區
5.7.3. 分區連接(partitionwise join)
5.7.3.1. 只有那些包含查詢所需數據的分區才會被包含在內
5.7.4. 能夠快速刪除不再需要的數據
5.7.4.1. 財務數據可能需要線上保存7年,如果數據表已根據事務日期進行分區,就可以撤銷數據保存時長超過7年的分區
5.7.5. 能夠同時更新多個分區,這可以大大減少數據表中每行所需的處理時間
5.8. 管理特性
5.8.1. 分區可以存儲在不同的表空間中,表空間可以位於不同的物理存儲層
5.8.2. 可以使用不同的壓縮方案來壓縮分區
5.8.3. 可以撤銷某些分區的本地索引
5.8.4. 可以在某些分區上凍結數據表的統計信息,同時在其他分區上定期刷新
5.8.5. 單個分區可以固定在記憶體中或存儲在資料庫的快閃記憶體存儲層中
5.9. 數據表分區
5.9.1. 水平分區
5.9.1.1. 將整行分配給一個分區
5.9.2. 垂直分區
5.9.2.1. 將列集分配給不同的分區,但必須手動完成
5.10. 索引分區
5.10.1. 全局索引
5.10.1.1. 如果經過分區的數據表有索引,可以選擇特定的索引保持原樣
5.10.1.2. 跨越數據表的所有分區,對於沒有指定分區鍵值的查詢很有用
5.10.2. 局部索引
5.10.2.1. 劃分成幾個部分,使每個分區有自己的索引
5.11. 分區方法
5.11.1. 範圍分區
5.11.1.1. range partitioning
5.11.1.2. 第一種被實現的分區方法
5.11.1.3. 使用最廣泛的方法
5.11.1.4. 允許一個maxvalue分區捕獲任何沒有映射到其他分區的行
5.11.1.5. mysql
-> CREATE TABLE sales
-> (sale_id INT NOT NULL,
-> cust_id INT NOT NULL,
-> store_id INT NOT NULL,
-> sale_date DATE NOT NULL,
-> amount DECIMAL(9,2)
-> )
-> PARTITION BY RANGE (yearweek(sale_date))
-> (PARTITION s1 VALUES LESS THAN (202002),
-> PARTITION s2 VALUES LESS THAN (202003),
-> PARTITION s3 VALUES LESS THAN (202004),
-> PARTITION s4 VALUES LESS THAN (202005),
-> PARTITION s5 VALUES LESS THAN (202006),
-> PARTITION s999 VALUES LESS THAN (MAXVALUE)
-> );
5.11.1.6. sql
ALTER TABLE sales REORGANIZE PARTITION s999 INTO
(PARTITION s6 VALUES LESS THAN (202007),
PARTITION s7 VALUES LESS THAN (202008),
PARTITION s999 VALUES LESS THAN (MAXVALUE)
);
5.11.1.7. 使用information_schema資料庫中的partitions數據表
5.11.1.8. mysql
-> SELECT partition_name, partition_method, partition_expression
-> FROM information_schema.partitions
-> WHERE table_name = 'sales'
-> ORDER BY partition_ordinal_position;
5.11.2. 列表分區
5.11.2.1. 選擇作為分區鍵的列包含州編碼(例如CA、TX、VA等)、貨幣(例如USD、EUR、JPY等)或其他一些枚舉值集
5.11.2.2. 它允許指定將哪些值分配給各個分區
5.11.2.3. 不提供溢出分區(spillover partition)
5.11.2.3.1. 添加另一個列值,就得修改分區定義,然後才能將包含新值的行添加到數據表中
5.11.2.4. mysql
-> CREATE TABLE sales
-> (sale_id INT NOT NULL,
-> cust_id INT NOT NULL,
-> store_id INT NOT NULL,
-> sale_date DATE NOT NULL,
-> geo_region_cd VARCHAR(6) NOT NULL,
-> amount DECIMAL(9,2)
-> )
-> PARTITION BY LIST COLUMNS (geo_region_cd)
-> (PARTITION NORTHAMERICA VALUES IN ('US_NE','US_SE','US_MW',
-> 'US_NW','US_SW','CAN','MEX'),
-> PARTITION EUROPE VALUES IN ('EUR_E','EUR_W'),
-> PARTITION ASIA VALUES IN ('CHN','JPN','IND')
-> );
5.11.2.5. mysql
-> ALTER TABLE sales REORGANIZE PARTITION ASIA INTO
-> (PARTITION ASIA VALUES IN ('CHN','JPN','IND', 'KOR'));
5.11.3. 哈希分區
5.11.3.1. hash partition
5.11.3.2. 儘力將行均勻地分佈在一組分區中
5.11.3.3. 不同於列表分區(選擇作為分區鍵的列應該包含少量值),哈希分區的分區鍵列在包含大量不同值時效果最佳
5.11.3.4. mysql
-> CREATE TABLE sales
-> (sale_id INT NOT NULL,
-> cust_id INT NOT NULL,
-> store_id INT NOT NULL,
-> sale_date DATE NOT NULL,
-> amount DECIMAL(9,2)
-> )
-> PARTITION BY HASH (cust_id)
-> PARTITIONS 4
-> (PARTITION H1,
-> PARTITION H2,
-> PARTITION H3,
-> PARTITION H4
-> );
5.11.4. 複合分區
5.11.4.1. composite partition
5.11.4.2. 允許對同一個數據表使用兩種不同類型的分區
5.11.4.2.1. 第一種分區方法定義了分區
5.11.4.2.2. 第二種分區方法定義了子分區
5.11.4.3. mysql
-> CREATE TABLE sales
-> (sale_id INT NOT NULL,
-> cust_id INT NOT NULL,
-> store_id INT NOT NULL,
-> sale_date DATE NOT NULL,
-> amount DECIMAL(9,2)
-> )
-> PARTITION BY RANGE (yearweek(sale_date))
-> SUBPARTITION Y HASH (cust_id)
-> (PARTITION s1 VALUES LESS THAN (202002)
-> (SUBPARTITION s1_h1,
-> SUBPARTITION s1_h2,
-> SUBPARTITION s1_h3,
-> SUBPARTITION s1_h4),
-> PARTITION s2 VALUES LESS THAN (202003)
-> (SUBPARTITION s2_h1,
-> SUBPARTITION s2_h2,
-> SUBPARTITION s2_h3,
-> SUBPARTITION s2_h4),
-> PARTITION s3 VALUES LESS THAN (202004)
-> (SUBPARTITION s3_h1,
-> SUBPARTITION s3_h2,
-> SUBPARTITION s3_h3,
-> SUBPARTITION s3_h4),
-> PARTITION s4 VALUES LESS THAN (202005)
-> (SUBPARTITION s4_h1,
-> SUBPARTITION s4_h2,
-> SUBPARTITION s4_h3,
-> SUBPARTITION s4_h4),
-> PARTITION s5 VALUES LESS THAN (202006)
-> (SUBPARTITION s5_h1,
-> SUBPARTITION s5_h2,
-> SUBPARTITION s5_h3,
-> SUBPARTITION s5_h4),
-> PARTITION s999 VALUES LESS THAN (MAXVALUE)
-> (SUBPARTITION s999_h1,
-> SUBPARTITION s999_h2,
-> SUBPARTITION s999_h3,
-> SUBPARTITION s999_h4)
-> );
6. 集群
6.1. clustering
6.2. 允許將多個伺服器用作單個資料庫
6.3. 共用磁碟/共用緩存的配置
6.3.1. shared-disk/shared-cache configuration
6.3.2. 集群中的每個伺服器都可以訪問所有磁碟,緩存在一個伺服器中的數據可以被集群中的其他伺服器訪問
6.4. Oracle Exadata平臺托管可供數千個併發用戶訪問的超大型資料庫
6.4.1. 該平臺仍無法滿足更大型公司的需求,這導致Google、Facebook、Amazon等公司另闢新徑
7. 分片
7.1. 對單個數據表和整個資料庫進行分區
7.2. 跨多個資料庫對數據進行分區,類似於數據表分區,但規模更大,複雜性也高得多
7.3. 需要選擇一個分片鍵,用於決定連接到哪個資料庫
7.4. 單獨的行分配給單個分片,但較小的參考表可能需要複製到所有分片上,同時還要定義相應的策略,以決定如何修改參考數據並將改動傳播給所有分片
7.5. 如果單個分片變得過大(例如社交媒體公司現在擁有了20億用戶),就需要計劃添加更多的分片並將數據重新分佈在分片中
7.6. 當需要變更模式時,要定義相應的策略,用於在所有分片上部署變更,以便模式保持同步
7.7. 如果應用程式邏輯需要訪問存儲在多個分片中的數據,要定義相應的策略,以決定如何跨資料庫查詢以及如何實現跨資料庫事務
8. 大數據
8.1. 容量(Volume)
8.1.1. 常意味著數十億或數萬億數據點
8.2. 速度(Velocity)
8.2.1. 對數據到達速度的一種衡量
8.3. 多樣性(Variety)
8.3.1. 文檔資料庫屬於所謂的NoSQL資料庫的子集,通常使用簡單的“鍵-值”機制存儲數據
8.3.2. MongoDB是用於文檔存儲的一種比較流行的NoSQL平臺
8.4. Hadoop分散式文件系統
8.4.1. Hadoop Distributed File System,HDFS
8.4.2. HDFS允許跨很多個伺服器管理文件
8.5. MapReduce
8.5.1. 該技術通過將任務分解為可以在多個伺服器上並行運行的許多細小部分來處理大量結構化數據和非結構化數據
8.6. YARN
8.6.1. 用於HDFS的資源管理器和作業調度器
8.7. 允許像單一邏輯系統那樣在數百甚至數千台伺服器上存儲和處理文件
8.8. Hive
8.8.1. 允許用戶查詢存儲在Hadoop中數據的初期嘗試之一
8.9. Spark SQL
8.9.1. 一個庫,用於查詢以各種格式存儲在Spark中的數據
9. Presto
10. Toad Data Point
11. Apache Drill
11.1. 初現於2015年
11.2. 更像是一個抽象層,促進了跨各種資料庫平臺的數據分析
11.3. 特性
11.3.1. 促進跨多種數據格式的查詢,包括分隔數據、JSON、Parquet和日誌文件
11.3.2. 連接到關係型資料庫、Hadoop、NoSQL、HBase、Kafka,以及PCAP、BlockChain等專用數據格式
11.3.3. 允許創建自定義插件,以連接到大多數其他數據存儲
11.3.4. 不需要前期的模式定義
11.3.5. 支持SQL:2003標準
11.3.6. 可與Tableau、Apache Superset等流行的商業智能(business intelligence,BI)工具配合使用
11.3.7. 可以連接到任意數量的數據源進行查詢,無須先設置元數據倉庫
11.4. 查詢文件
11.4.1. sql
apache drill> SELECT file_name, is_directory, is_file, permission
. . . . . . > FROM information_schema.`files`
. . . . . . > WHERE schema_name = 'dfs.data';
11.5. 查詢MySQL
11.5.1. apache drill (information_schema)> use mysql.sakila;
11.5.2. apache drill (mysql.sakila)> show tables;
11.5.3. apache drill (mysql.sakila)
)> SELECT a.address_id, a.address, ct.city
)> FROM address a
)> INNER JOIN city ct
)> ON a.city_id = ct.city_id
)> WHERE a.district = 'California';
11.6. 查詢MongoDB
11.6.1. apache drill (mongo.sakila)
)> SELECT Rating, Actors
)> FROM films
)> WHERE Rating IN ('G','PG');
11.7. 處理多個數據源
11.7.1. 在同一個查詢中組合多個來源的數據,而無須將一個來源的數據轉換並載入到另一個來源
11.7.2. apache drill (mongo.sakila)
)> SELECT first_name, last_name,
)> sum(cast(cust_payments.payment_data.Amount
)> as decimal(4,2))) tot_payments
)> FROM
)> (SELECT cust_data.first_name,
)> cust_data.last_name,
)> f.Rating,
)> flatten(cust_data.rental_data.Payments)
)> payment_data
)> FROM mysql.sakila.film f
)> INNER JOIN
)> (SELECT c.`First Name` first_name,
)> c.`Last Name` last_name,
)> flatten(c.Rentals) rental_data
)> FROM mongo.sakila.customers c
)> ) cust_data
)> ON f.film_id =
)> cast(cust_data.rental_data.filmID as integer)
)> WHERE f.rating IN ('G','PG')
)> ) cust_payments
)> GROUP BY first_name, last_name
)> HAVING
)> sum(cast(cust_payments.payment_data.Amount
)> as decimal(4,2))) > 80;