sql: SQL Data Sampling and Approximation Techniques using mysql 9.0
CREATE DATABASE IF NOT EXISTS JewelryAnalytics DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
USE JewelryAnalytics;
SET SESSION cte_max_recursion_depth=1000000;
SET SESSION group_concat_max_len=1000000;
SET SESSION optimizer_switch='index_condition_pushdown=on,mrr=on,derived_merge=on,skip_scan=on';
SET SESSION transaction_isolation='REPEATABLE-READ';
SET SESSION sql_safe_updates=0;
SET SESSION innodb_lock_wait_timeout=50;
SET SESSION time_zone='+00:00';
SET SESSION max_execution_time=0;
-- ============================================================================
-- §0.0 运行方式必读(务必先读)
-- ============================================================================
-- 本脚本:MySQL 9.0 数据采样与近似聚合(Sampling & Approximation)
-- 主题:国际化珠宝集团 OA/ERP/CRM/HRM/MES/SCM/WMS/KMS 八域交易数据
-- + 万亿高并发 + 国际时区 + 多币种结算 下的"快但够用"的估算技术
-- 运行前提:MySQL 9.0.x,库 JewelryAnalytics 自动建/用;本脚本完全幂等。
-- 方式A(命令行,推荐,避开 Workbench 30s 读超时):
-- mysql -uroot -p --default-character-set=utf8mb4 < MySQL9_SamplingApprox_JewelryDemo.sql
-- 方式B(Workbench):整段执行。
-- 幂等说明:每次先 DROP 全部 samp_* 实验表/过程再重建造数,重复运行结果一致。
-- 度量口径:performance_schema.session_status 的 INNODB_ROWS_READ / CREATED_TMP_TABLES /
-- SORT_ROWS 增量,量化"引擎真实代价",证明采样/近似省在哪。
-- ============================================================================
-- §0.1 MySQL 采样/近似能力速览(与其它数据库术语映射)
-- ----------------------------------------------------------------------------
-- ANSI/PG/SQLServer MySQL 9.0 等价实现
-- ----------------------------- -------------------------------------------------
-- TABLESAMPLE SYSTEM(n) 无原生支持 → 用 WHERE MOD(pk,n)=r(系统抽样)
-- TABLESAMPLE BERNOULLI(p) 无原生支持 → 用 WHERE RAND()<p(伯努利抽样)
-- APPROX_COUNT_DISTINCT(col) 本实例 9.0.1 未提供;改用「采样外推/捕获-重捕」或下沉 ES
-- COUNT(DISTINCT col) 精确去重(通常建临时表,贵)
-- 列直方图 / 近似分布 ANALYZE TABLE t UPDATE HISTOGRAM ON c WITH N BUCKETS
-- 物化视图 / 预聚合 MySQL 无物化视图 → 用"汇总表(rollup)"手工预聚合
-- 优化器估算行数 EXPLAIN 的 rows 列(便宜的近似结果量)
-- ============================================================================
-- §0.2 反模式速查表(本机已实测)
-- ----------------------------------------------------------------------------
-- 反模式 后果 正确做法
-- ORDER BY RAND() LIMIT n 全表扫描+filesort,深数据灾难 WHERE MOD(pk,n)=r 系统抽样
-- RAND()<p 抽样当审计依据 RAND() 非确定,结果不可重放 用 MOD 确定性抽样(可复现)
-- 采样外推/近似聚合做合规对账 有偏有误差,合规不允 精确场合用 COUNT(DISTINCT) 全量
-- MOD(id,10)=0 假设 id 均匀 若 id 按区域分块→抽样有偏 分层抽样(系统内 MOD)
-- 跨币种 SUM(amount_orig) 抽样 混合币种+仅样本=双重错误 只 SUM(amount_usd)
-- 按 created_ts(UTC) 抽"本地日" UTC 切割本地日→样本错位 用 create_local_date 生成列
-- 以为 MySQL 有 TABLESAMPLE 报错 1064 用 MOD/RAND/预聚合代替
-- 直方图不更新就查 优化器仍用旧统计 ANALYZE TABLE UPDATE HISTOGRAM
-- ============================================================================
-- §01 度量框架(samp_demo_*):量化引擎真实代价
DROP TABLE IF EXISTS samp_demo_metric;
CREATE TABLE samp_demo_metric(
tag VARCHAR(40) PRIMARY KEY,
innodb_rows BIGINT NOT NULL DEFAULT 0,
rnd_next BIGINT NOT NULL DEFAULT 0,
rnd BIGINT NOT NULL DEFAULT 0,
tmp_tables BIGINT NOT NULL DEFAULT 0,
sort_rows BIGINT NOT NULL DEFAULT 0,
ms INT NOT NULL DEFAULT 0,
note VARCHAR(255)
);
DROP TABLE IF EXISTS samp_demo_result;
CREATE TABLE samp_demo_result(
check_id VARCHAR(30) PRIMARY KEY,
passed TINYINT NOT NULL,
detail VARCHAR(400)
);
DROP TABLE IF EXISTS samp_demo_probe;
CREATE TABLE samp_demo_probe(
id INT AUTO_INCREMENT PRIMARY KEY,
label VARCHAR(60),
errno INT,
sql_state VARCHAR(10),
msg VARCHAR(300),
caught_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
DROP PROCEDURE IF EXISTS samp_snap;
DELIMITER //
CREATE PROCEDURE samp_snap()
BEGIN
SELECT VARIABLE_VALUE INTO @s_ir FROM performance_schema.session_status WHERE VARIABLE_NAME='INNODB_ROWS_READ';
SELECT VARIABLE_VALUE INTO @s_rn FROM performance_schema.session_status WHERE VARIABLE_NAME='HANDLER_READ_RND_NEXT';
SELECT VARIABLE_VALUE INTO @s_rd FROM performance_schema.session_status WHERE VARIABLE_NAME='HANDLER_READ_RND';
SELECT VARIABLE_VALUE INTO @s_tt FROM performance_schema.session_status WHERE VARIABLE_NAME='CREATED_TMP_TABLES';
SELECT VARIABLE_VALUE INTO @s_sr FROM performance_schema.session_status WHERE VARIABLE_NAME='SORT_ROWS';
SET @s_ts = UNIX_TIMESTAMP(NOW(6));
END//
DELIMITER ;
DROP PROCEDURE IF EXISTS samp_measure;
DELIMITER //
CREATE PROCEDURE samp_measure(IN p_tag VARCHAR(40))
BEGIN
DECLARE v_ir BIGINT; DECLARE v_rn BIGINT; DECLARE v_rd BIGINT; DECLARE v_tt BIGINT; DECLARE v_sr BIGINT; DECLARE v_ms INT;
SELECT VARIABLE_VALUE INTO v_ir FROM performance_schema.session_status WHERE VARIABLE_NAME='INNODB_ROWS_READ';
SELECT VARIABLE_VALUE INTO v_rn FROM performance_schema.session_status WHERE VARIABLE_NAME='HANDLER_READ_RND_NEXT';
SELECT VARIABLE_VALUE INTO v_rd FROM performance_schema.session_status WHERE VARIABLE_NAME='HANDLER_READ_RND';
SELECT VARIABLE_VALUE INTO v_tt FROM performance_schema.session_status WHERE VARIABLE_NAME='CREATED_TMP_TABLES';
SELECT VARIABLE_VALUE INTO v_sr FROM performance_schema.session_status WHERE VARIABLE_NAME='SORT_ROWS';
SET v_ms = ROUND((UNIX_TIMESTAMP(NOW(6)) - @s_ts)*1000);
INSERT INTO samp_demo_metric(tag,innodb_rows,rnd_next,rnd,tmp_tables,sort_rows,ms) VALUES(p_tag, v_ir-@s_ir, v_rn-@s_rn, v_rd-@s_rd, v_tt-@s_tt, v_sr-@s_sr, v_ms)
ON DUPLICATE KEY UPDATE innodb_rows=v_ir-@s_ir, rnd_next=v_rn-@s_rn, rnd=v_rd-@s_rd, tmp_tables=v_tt-@s_tt, sort_rows=v_sr-@s_sr, ms=v_ms;
END//
DELIMITER ;
DROP PROCEDURE IF EXISTS samp_v;
DELIMITER //
CREATE PROCEDURE samp_v(IN p_check VARCHAR(30), IN p_pass TINYINT, IN p_detail VARCHAR(400))
BEGIN
INSERT INTO samp_demo_result(check_id,passed,detail) VALUES(p_check,p_pass,p_detail)
ON DUPLICATE KEY UPDATE passed=p_pass, detail=p_detail;
END//
DELIMITER ;
DROP PROCEDURE IF EXISTS samp_err_probe;
DELIMITER //
CREATE PROCEDURE samp_err_probe(IN p_label VARCHAR(60), IN p_sql TEXT)
BEGIN
DECLARE v_no INT DEFAULT 0; DECLARE v_st VARCHAR(10) DEFAULT '00000'; DECLARE v_msg VARCHAR(300) DEFAULT '';
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
BEGIN
GET DIAGNOSTICS CONDITION 1 v_no = MYSQL_ERRNO, v_st = RETURNED_SQLSTATE, v_msg = MESSAGE_TEXT;
END;
SET @samp_probe_sql = p_sql;
PREPARE samp_pstmt FROM @samp_probe_sql;
IF v_no = 0 THEN
EXECUTE samp_pstmt;
DEALLOCATE PREPARE samp_pstmt;
END IF;
INSERT INTO samp_demo_probe(label,errno,sql_state,msg) VALUES(p_label, v_no, v_st, v_msg);
END//
DELIMITER ;
-- §02 实验台:八域交易事实表 + 维度表 + 造数(国际化珠宝集团)
DROP TABLE IF EXISTS samp_dim_currency;
CREATE TABLE samp_dim_currency(code CHAR(3) PRIMARY KEY, name VARCHAR(40), symbol VARCHAR(8), usd_rate DECIMAL(12,6));
INSERT INTO samp_dim_currency VALUES
('CNY','人民币','¥',1/7.20),('USD','美元','$',1.0),('EUR','欧元','€',1.08),
('JPY','日元','¥',0.0067),('HKD','港元','HK$',1/7.80),('GBP','英镑','£',1.27);
DROP TABLE IF EXISTS samp_dim_country;
CREATE TABLE samp_dim_country(code CHAR(2) PRIMARY KEY, name VARCHAR(40), tz_offset_min INT, currency CHAR(3));
INSERT INTO samp_dim_country VALUES
('CN','中国',480,'CNY'),('US','美国',-300,'USD'),('FR','法国',60,'EUR'),
('JP','日本',540,'JPY'),('HK','中国香港',480,'HKD'),('GB','英国',0,'GBP'),
('DE','德国',60,'EUR'),('SG','新加坡',480,'USD');
-- 八域交易事实表(采样/近似主战场)
DROP TABLE IF EXISTS samp_txn;
CREATE TABLE samp_txn(
txn_id BIGINT PRIMARY KEY,
system_code CHAR(4) NOT NULL, -- OA/ERP/CRM/HRM/MES/SCM/WMS/KMS
doc_type VARCHAR(30),
customer_id INT NOT NULL,
category VARCHAR(20),
channel VARCHAR(20),
country_code CHAR(2),
currency_code CHAR(3),
amount_orig DECIMAL(18,2),
amount_usd DECIMAL(18,2), -- 已按汇率归一,结算只用它
create_offset_min SMALLINT, -- 时区偏移(分钟),冗余以便生成列建索引
created_ts DATETIME NOT NULL, -- 统一存 UTC
create_local_date DATE -- 生成列:本地营业日,用于带索引的时区过滤
GENERATED ALWAYS AS (DATE(TIMESTAMPADD(MINUTE, create_offset_min, created_ts))) STORED,
KEY ix_system (system_code),
KEY ix_local_date (create_local_date),
KEY ix_usd (amount_usd),
KEY ix_customer (customer_id)
) ENGINE=InnoDB;
-- 造 200,000 行(500×400),八域、多国、多币种、中英混排、UTC 时间
INSERT INTO samp_txn(txn_id,system_code,doc_type,customer_id,category,channel,country_code,currency_code,amount_orig,amount_usd,create_offset_min,created_ts)
WITH RECURSIVE a(n) AS (SELECT 1 UNION ALL SELECT n+1 FROM a WHERE n<500),
b(n) AS (SELECT 1 UNION ALL SELECT n+1 FROM b WHERE n<400),
base AS (SELECT a.n*400 + b.n - 400 AS id FROM a JOIN b),
enriched AS (
SELECT
id,
ELT(1+id%8,'OA','ERP','CRM','HRM','MES','SCM','WMS','KMS') AS sys,
ELT(1+id%10,'黄金','铂金','钻石','红宝石','蓝宝石','翡翠','珍珠','银','18K金','白金') AS cat,
ELT(1+id%5,'门店','官网','微信','展会','经销商') AS ch,
(id % 60000) + 1 AS cust, -- 约 60000 个独立客户(高基数列,供近似去重演示)
ELT(1+id%8,'CN','US','FR','JP','HK','GB','DE','SG') AS ctry,
ELT(1+id%6,'采购','报销','合同','工单','运单','知识') AS dtype,
ROUND(50 + (id%9500)/10.0, 2) AS amt
FROM base
)
SELECT
id, sys, dtype, cust, cat, ch, ctry,
ELT(FIELD(ctry,'CN','US','FR','JP','HK','GB','DE','SG'),'CNY','USD','EUR','JPY','HKD','GBP','EUR','USD') AS cur,
amt,
ROUND(amt * ELT(FIELD(ctry,'CN','US','FR','JP','HK','GB','DE','SG'),1/7.20,1.0,1.08,0.0067,1/7.80,1.27,1.08,1.0), 2) AS amt_usd,
ELT(FIELD(ctry,'CN','US','FR','JP','HK','GB','DE','SG'),480,-300,60,540,480,0,60,480) AS off,
DATE_ADD('2025-09-01 00:00:00', INTERVAL (id % 365) DAY) + INTERVAL (id % 86400) SECOND AS cts
FROM enriched;
-- §03 近似聚合(采样外推):MySQL 9.0.1 无内置 HLL 近似去重,用「采样+外推」做快估
SELECT '§03 近似聚合:采样外推 SUM/COUNT(MySQL 无内置 HLL 近似去重)' AS `-- 第3章 --`;
-- 3.1 精确总量
SELECT COUNT(*) INTO @total_rows FROM samp_txn;
SELECT SUM(amount_usd) INTO @exact_gmv FROM samp_txn;
-- 3.2 近似总量:伯努利抽样 RAND()<0.05(对 id 独立、无系统性偏差),按 1/抽样率 外推
SELECT COUNT(*), SUM(amount_usd) INTO @s_rows, @s_gmv FROM samp_txn WHERE RAND() < 0.05;
SET @approx_gmv = @s_gmv * (@total_rows / @s_rows);
-- 3.3 度量:精确聚合全扫 vs 伯努利采样聚合(抽样对 id 独立,无偏)
CALL samp_snap();
SELECT SUM(amount_usd) INTO @x1 FROM samp_txn;
CALL samp_measure('EXACT_agg');
CALL samp_snap();
SELECT SUM(amount_usd) INTO @x2 FROM samp_txn WHERE RAND() < 0.05;
CALL samp_measure('SAMPLE_agg');
SELECT '精确GMV_usd=' AS `-- `, @exact_gmv, '近似GMV_usd=' AS `-- `, @approx_gmv,
CONCAT('误差=', ROUND(100*(@approx_gmv-@exact_gmv)/@exact_gmv,3), '%') AS `误差`;
-- 3.4 近似「独立客户数」是难题:需独立随机抽样或 HLL;周期性 MOD 抽样会破坏独立性,
-- 不能直接套捕获-重捕(Lincoln-Petersen)。生产用应用层 HLL 或下沉 Elasticsearch。此处只演示 SUM 外推。
-- §04 系统抽样(Systematic):MOD(pk) 确定性、可复现、走主键
SELECT '§04 系统抽样 MOD(pk,n)=r:确定性、可复现、万亿级友好' AS `-- 第4章 --`;
SELECT COUNT(*) INTO @sys_sample FROM samp_txn WHERE MOD(txn_id,10)=0; -- 期望 ~10% = 20000
-- 分层抽样:每个 system_code 内部各取 10%(避免 id 按域分块导致的偏差)
SELECT system_code, COUNT(*) AS stratum_rows,
SUM(MOD(txn_id,10)=0) AS sampled_in_stratum
FROM samp_txn GROUP BY system_code ORDER BY system_code;
-- §05 伯努利抽样(Bernoulli):RAND()<p(全扫但无排序);及 ORDER BY RAND() 灾难
SELECT '§05 伯努利抽样 RAND()<p vs ORDER BY RAND() 灾难' AS `-- 第5章 --`;
SELECT COUNT(*) INTO @bern_sample FROM samp_txn WHERE RAND() < 0.01; -- 期望 ~1% = 2000
-- 度量:ORDER BY RAND() LIMIT(全量 RAND 计算+堆排,CPU 重)vs MOD 系统抽样(整数运算、无随机)
CALL samp_snap();
SELECT COUNT(*) INTO @r1 FROM samp_txn ORDER BY RAND() LIMIT 1000;
CALL samp_measure('RAND_sort');
CALL samp_snap();
SELECT COUNT(*) INTO @r2 FROM samp_txn WHERE MOD(txn_id,10)=0 LIMIT 1000;
CALL samp_measure('MOD_sample');
-- 非确定性演示:ORDER BY RAND() LIMIT 1 的首行 ≠ 确定性 ORDER BY txn_id LIMIT 1 的首行(不可重放)
SELECT txn_id INTO @ra FROM samp_txn ORDER BY RAND() LIMIT 1;
SELECT txn_id INTO @rd FROM samp_txn ORDER BY txn_id LIMIT 1;
-- §06 预聚合汇总表(rollup):万亿级"近似"正解——查 O(小) 而非扫全表
SELECT '§06 预聚合汇总表(rollup):万亿级近似/实时看板的正确姿势' AS `-- 第6章 --`;
DROP TABLE IF EXISTS samp_daily_rollup;
CREATE TABLE samp_daily_rollup(
local_date DATE NOT NULL,
system_code CHAR(4) NOT NULL,
currency_code CHAR(3) NOT NULL,
txn_cnt BIGINT NOT NULL,
gmv_usd DECIMAL(20,2) NOT NULL,
approx_buyers BIGINT NOT NULL,
PRIMARY KEY (local_date, system_code, currency_code)
) ENGINE=InnoDB;
INSERT INTO samp_daily_rollup(local_date, system_code, currency_code, txn_cnt, gmv_usd, approx_buyers)
SELECT create_local_date, system_code, currency_code,
COUNT(*), SUM(amount_usd), COUNT(DISTINCT customer_id)
FROM samp_txn
GROUP BY create_local_date, system_code, currency_code;
-- 万亿级查询:直接读 rollup(O(几百行)),不再扫事实表
SELECT system_code, SUM(txn_cnt) AS total_txn, ROUND(SUM(gmv_usd),2) AS total_gmv_usd,
SUM(approx_buyers) AS approx_total_buyers
FROM samp_daily_rollup
GROUP BY system_code ORDER BY total_gmv_usd DESC;
-- §07 列直方图:ANALYZE TABLE UPDATE HISTOGRAM(近似分布/基数,供优化器与估算)
SELECT '§07 列直方图:UPDATE HISTOGRAM(近似分布)' AS `-- 第7章 --`;
ANALYZE TABLE samp_txn UPDATE HISTOGRAM ON amount_usd WITH 32 BUCKETS;
SELECT table_name, column_name,
JSON_EXTRACT(histogram, '$.last_updated') AS last_updated,
JSON_EXTRACT(histogram, '$.number_of_buckets') AS buckets
FROM information_schema.column_statistics
WHERE schema_name='JewelryAnalytics' AND table_name='samp_txn' AND column_name='amount_usd';
-- §08 EXPLAIN 估算行数:便宜的"近似结果量"
SELECT '§08 EXPLAIN 估算行数(优化器的近似)' AS `-- 第8章 --`;
EXPLAIN SELECT SUM(amount_usd) FROM samp_txn WHERE create_local_date='2025-12-25';
-- §09 国际时区 + 多币种 + 采样/近似 组合
SELECT '§09 时区/多币种 + 采样近似:本地日抽样、只用 amount_usd' AS `-- 第9章 --`;
-- 9.1 在"本地营业日"内做 10% 系统抽样,估算各域 GMV 与独立买家数
SELECT t.system_code, c.name AS country,
COUNT(*) AS sampled_rows,
ROUND(SUM(t.amount_usd),2) AS gmv_usd, -- 正确:归一美元
COUNT(DISTINCT t.customer_id) AS approx_buyers
FROM samp_txn t
JOIN samp_dim_country c ON c.code = t.country_code
WHERE t.create_local_date = '2025-12-25'
AND MOD(t.txn_id,10) = 0
GROUP BY t.system_code, c.name ORDER BY gmv_usd DESC;
-- 9.2 时区正确性:生成列非 NULL;TIMESTAMPADD 可用;CONVERT_TZ 本机为 NULL(已知)
SELECT TIMESTAMPADD(MINUTE,480,'2026-01-01 00:00:00') INTO @tz_chk;
SELECT CONVERT_TZ('2026-01-01 00:00:00','UTC','Asia/Shanghai') INTO @tz_null;
-- 9.3 多币种一致性:amount_usd 与 amount_orig*rate 全部一致
SELECT COUNT(*) INTO @cur_ok FROM samp_txn
WHERE ABS(amount_usd - ROUND(amount_orig * CASE currency_code WHEN 'CNY' THEN 1/7.20 WHEN 'USD' THEN 1 WHEN 'EUR' THEN 1.08 WHEN 'JPY' THEN 0.0067 WHEN 'HKD' THEN 1/7.80 WHEN 'GBP' THEN 1.27 END,2)) < 0.02;
SELECT COUNT(*) INTO @cur_tot FROM samp_txn;
-- §10 自检(V1..V12)全部通过才算交付
-- V1 框架表存在
SELECT COUNT(*) INTO @v1 FROM information_schema.tables WHERE table_schema='JewelryAnalytics' AND table_name IN ('samp_demo_metric','samp_demo_result','samp_demo_probe');
CALL samp_v('V1_框架表存在', IF(@v1=3,1,0), CONCAT('框架表数=',@v1));
-- V2 近似聚合(采样外推)可用且 >0
CALL samp_v('V2_近似聚合可用', IF(@approx_gmv>0,1,0), CONCAT('approx_gmv=',@approx_gmv));
-- V3 系统抽样 MOD 约 10%(5%~20%)
CALL samp_v('V3_系统抽样约10%', IF(@sys_sample BETWEEN 10000 AND 40000,1,0), CONCAT('抽样行=',@sys_sample,' 全量=200000'));
-- V4 直方图已生成
SELECT COUNT(*) INTO @v4 FROM information_schema.column_statistics
WHERE schema_name='JewelryAnalytics' AND table_name='samp_txn' AND column_name='amount_usd';
CALL samp_v('V4_直方图已生成', IF(@v4>=1,1,0), CONCAT('histogram条目=',@v4));
-- V5 rollup 汇总表存在且 GMV>0
SELECT IFNULL((SELECT SUM(gmv_usd) FROM samp_daily_rollup),0) INTO @v5;
CALL samp_v('V5_汇总表GMV>0', IF(@v5>0,1,0), CONCAT('rollup总GMV_usd=',@v5));
-- V6 时区:生成列可用;CONVERT_TZ 本机 NULL(已知)
CALL samp_v('V6_时区生成列可用', IF(@tz_chk IS NOT NULL AND @tz_null IS NULL,1,0), CONCAT('TSadd非NULL=',IF(@tz_chk IS NULL,'N','Y'),' CONVERT_TZ=',IF(@tz_null IS NULL,'NULL(已知)','有值')));
-- V7 多币种:amount_usd 与 amount_orig*rate 全部一致
CALL samp_v('V7_多币种USD归一一致', IF(@cur_ok=@cur_tot,1,0), CONCAT('一致=',@cur_ok,'/',@cur_tot));
-- V8 近似 vs 精确:GMV 外推误差 < 5%
CALL samp_v('V8_近似误差<5%', IF(@exact_gmv>0 AND ABS(@approx_gmv-@exact_gmv)/@exact_gmv < 0.05,1,0), CONCAT('exact_gmv=',@exact_gmv,' approx_gmv=',@approx_gmv,' 误差=',ROUND(100*(@approx_gmv-@exact_gmv)/@exact_gmv,3),'%'));
-- V9 ORDER BY RAND() 非确定(不可重放);MOD 系统抽样确定性可复现
CALL samp_v('V9_RAND非确定不可重放', IF(@ra <> @rd,1,0), CONCAT('rand首行=',@ra,' 确定首行=',@rd));
-- V10 预聚合汇总表读行远少于事实表全扫(万亿级成本赢点)
CALL samp_snap();
SELECT SUM(gmv_usd) INTO @x3 FROM samp_daily_rollup;
CALL samp_measure('ROLLUP_agg');
SELECT IFNULL((SELECT innodb_rows FROM samp_demo_metric WHERE tag='EXACT_agg'),0) INTO @ir_exact;
SELECT IFNULL((SELECT innodb_rows FROM samp_demo_metric WHERE tag='ROLLUP_agg'),0) INTO @ir_rollup;
CALL samp_v('V10_汇总表读行远少于事实表', IF(@ir_exact > @ir_rollup,1,0), CONCAT('事实表读行=',@ir_exact,' 汇总表读行=',@ir_rollup));
-- V11 错误探针:MySQL 无 ANSI TABLESAMPLE → 报错(演示替代方案必要)
CALL samp_err_probe('MySQL无TABLESAMPLE', 'SELECT * FROM samp_txn TABLESAMPLE SYSTEM(10)');
SELECT IFNULL((SELECT errno FROM samp_demo_probe WHERE label='MySQL无TABLESAMPLE' ORDER BY id DESC LIMIT 1),0) INTO @v11;
CALL samp_v('V11_TABLESAMPLE不支持', IF(@v11>0,1,0), CONCAT('捕获errno=',@v11));
-- V12 幂等:交易事实表量稳定 = 200000
SELECT COUNT(*) INTO @v12 FROM samp_txn;
CALL samp_v('V12_数据量稳定200000', IF(@v12=200000,1,0), CONCAT('txn行数=',@v12));
SELECT '==== 自检汇总:以下应全部 passed=1 ====' AS `-- 自检 --`;
SELECT check_id, passed, detail FROM samp_demo_result ORDER BY check_id;
-- §11 实测总表与结论
SELECT '§11.1 引擎真实代价对照(增量)' AS `-- 第11章 --`;
SELECT tag, innodb_rows AS 引擎读行, tmp_tables AS 临时表, sort_rows AS 排序行, ms AS 耗时ms, note
FROM samp_demo_metric ORDER BY tag;
SELECT '§11.2 错误探针(预期捕获,非致命)' AS `-- 第11章 --`;
SELECT label, errno, msg FROM samp_demo_probe ORDER BY id;
SELECT '§11.3 自检结果(全部 passed=1 为通过)' AS `-- 第11章 --`;
SELECT check_id, passed, detail FROM samp_demo_result ORDER BY check_id;
SELECT '§11.4 关键结论' AS `-- 第11章 --`;
SELECT '1) MySQL 无 ANSI TABLESAMPLE;系统抽样用 MOD(pk,n)=r(确定性、可复现、走主键)。' AS `结论1`;
SELECT '2) MySQL 9.0.1 无内置 HLL 近似去重;用「采样外推 SUM」或「捕获-重捕」估独立客户数,或下沉 ES。' AS `结论2`;
SELECT '3) ORDER BY RAND() LIMIT n = 全表扫描+filesort,深数据灾难;抽样请改用 MOD 或预聚合。' AS `结论3`;
SELECT '4) RAND() 非确定,结果不可重放;审计/对账需可复现时禁用,用 MOD 确定性抽样。' AS `结论4`;
SELECT '5) 万亿级"近似"正解=预聚合汇总表(rollup):查 O(小) 而非扫全表;MySQL 无物化视图靠手工 rollup。' AS `结论5`;
SELECT '6) 列直方图(ANALYZE TABLE UPDATE HISTOGRAM)给优化器近似分布;EXPLAIN rows 是便宜的结果量近似。' AS `结论6`;
SELECT '7) 时区存 UTC,抽样按生成列 create_local_date(本地日) 过滤;多币种只 SUM(amount_usd)。' AS `结论7`;
SELECT '8) 精确场合(对账/合规)用 COUNT(DISTINCT) 全量;近似(看板/探索)才用采样外推或下沉 ES。' AS `结论8`;
SELECT '§11.5 八条方法清单(落到建表/查询)' AS `-- 第11章 --`;
SELECT '① 大盘近似用「采样外推」或下沉 ES(MySQL 无 HLL 近似去重);② 抽样用 MOD(pk,n) 确定性;③ 禁 ORDER BY RAND();' AS `清单`;
SELECT '④ 万亿级建 rollup 汇总表做近似/实时;⑤ 用 ANALYZE TABLE 更新直方图;⑥ 用 EXPLAIN 估算行数;' AS `清单`;
SELECT '⑦ 时区用生成列本地日+索引;⑧ 精确对账用 COUNT(DISTINCT),只 SUM(amount_usd)。' AS `清单`;
SELECT '§11.6 脚本结构' AS `-- 第11章 --`;
SELECT '_s00 头部/速览/反模式;_s01 度量框架;_s02 八域建表造数;_s03 采样外推近似;' AS `结构`;
SELECT '_s04 系统抽样;_s05 伯努利/ORDER BY RAND陷阱;_s06 rollup;_s07 直方图;_s08 EXPLAIN;_s09 时区/多币种;_s10 自检;_s11 总结。' AS `结构`;
哲学管理(学)人生, 文学艺术生活, 自动(计算机学)物理(学)工作, 生物(学)化学逆境, 历史(学)测绘(学)时间, 经济(学)数学金钱(理财), 心理(学)医学情绪, 诗词美容情感, 美学建筑(学)家园, 解构建构(分析)整合学习, 智商情商(IQ、EQ)运筹(学)生存.---Geovin Du(涂聚文)
浙公网安备 33010602011771号