ClickHouse复杂查询单表亿级数据案例(可导出Excel)

news2024/9/25 16:33:21

通过本篇博客,读者可以了解到如何在 ClickHouse 中高效地创建和管理大规模销售数据。随机数据生成和复杂查询的示例展示了 ClickHouse 的强大性能和灵活性。掌握这些技能后,用户能够更好地进行数据分析和决策支持,提升业务洞察能力。

表结构准备

销售表

CREATE TABLE IF NOT EXISTS sales (
    id Int64,
    product_id Int64,
    quantity Int32,
    price Float64,
    timestamp DateTime,
    customer_id Int64,          -- 客户ID
    discount Float64 DEFAULT 0, -- 折扣
    total_amount Float64,       -- 总金额
    payment_method String,      -- 付款方式
    status String,              -- 订单状态
    shipping_address String,    -- 发货地址
    billing_address String,     -- 账单地址
    order_notes String,         -- 订单备注
    created_at DateTime,        -- 创建时间
    updated_at DateTime,        -- 更新时间
    shipping_cost Float64,      -- 运费
    tax Float64,                -- 税费
    order_source String,        -- 订单来源
    fulfillment_status String,   -- 履行状态
    product_name String,        -- 产品名称
    product_category String      -- 产品类别
) ENGINE = MergeTree()
ORDER BY timestamp;

数据准备

随机生成1亿数据(我用的2千万一次一次插入)

INSERT INTO sales (id, product_id, quantity, price, timestamp, customer_id, discount, total_amount, payment_method, status, shipping_address, billing_address, order_notes, created_at, updated_at, shipping_cost, tax, order_source, fulfillment_status, product_name, product_category) SELECT
    number AS id,
    rand() % 10000 AS product_id,
    round((rand() % 20) + 5) AS quantity,
    round((rand() % 1000) + 100, 2) AS price,
    now() - toIntervalDay(rand() % 3650) AS timestamp,
    rand() % 1000 AS customer_id,
    round(rand() % 50, 2) AS discount,
    round((quantity * price) * (1 - (discount / 100)), 2) AS total_amount,
    ['credit_card', 'paypal', 'bank_transfer', 'cash', 'gift_card'][(rand() % 5) + 1] AS payment_method,
    ['pending', 'completed', 'canceled', 'refunded'][(rand() % 4) + 1] AS status,
    concat('Shipping Address ', number) AS shipping_address,
    concat('Billing Address ', number) AS billing_address,
    concat('Order notes for order ', number) AS order_notes,
    now() - toIntervalDay(rand() % 3650) AS created_at,
    now() - toIntervalDay(rand() % 3650) AS updated_at,
    round((rand() % 100) + 10, 2) AS shipping_cost,
    round((rand() % 50) + 5, 2) AS tax,
    ['website', 'mobile_app', 'third_party'][(rand() % 3) + 1] AS order_source,
    ['not_fulfilled', 'fulfilled', 'partially_fulfilled'][(rand() % 3) + 1] AS fulfillment_status,
    concat('Product Name ', number) AS product_name,
    ['electronics', 'clothing', 'home', 'toys', 'books'][(rand() % 5) + 1] AS product_category
FROM numbers(20000000)

Query id: 1237aa3d-3596-4d76-ac1b-cd4854eaa7bd

↖ Progress: 17.40 million rows, 139.19 MB (1.44 million rows/s., 11.48 MB/s.) (1.0 CPU, 415.10 MB RAM)███████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████                       86%

在生成数据时,我们可以看到CPU的占用率已经大于单核

 PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND                                                                                                                                                                              
 114260 clickho+  20   0   10.4g   1.7g 339104 S 140.9  11.4   3:36.99 clickhouse-serv

执行插入完毕后,查询当前数据条数

select count(*) from sales

SELECT count(*)
FROM sales

Query id: aeb5a6f3-9776-4220-8f1a-abf1e5855943

   ┌───count()─┐
1. │ 100101000 │ -- 100.10 million
   └───────────┘

1 row in set. Elapsed: 0.001 sec.

较为复杂的指标查询语句

SELECT
    product_id,  -- 产品 ID
    SUM(quantity) AS total_quantity,  -- 总销售数量
    SUM(quantity * price) AS total_sales,  -- 总销售额
    AVG(price) AS average_price,  -- 平均价格
    COUNT(*) AS total_transactions,  -- 总交易次数
    MAX(price) AS max_price,  -- 最高价格
    MIN(price) AS min_price,  -- 最低价格
    SUM(quantity) / NULLIF(COUNT(*), 0) AS avg_quantity_per_transaction_count,  -- 每笔交易的平均数量
    SUM(quantity * price) / NULLIF(SUM(quantity), 0) AS avg_sales_per_unit,  -- 每单位的平均销售额
    SUM(quantity) / NULLIF(COUNT(DISTINCT timestamp), 0) AS avg_daily_sales,  -- 平均每日销售数量
    COUNT(DISTINCT timestamp) AS selling_days,  -- 销售天数
    SUM(quantity * price) / NULLIF(COUNT(DISTINCT timestamp), 0) AS avg_daily_sales_value,  -- 平均每日销售额
    SUM(quantity) / SUM(quantity * price) AS sales_conversion_rate,  -- 销售转化率
    COUNT(IF(price > 50, 1, NULL)) AS high_price_transactions,  -- 高价交易次数(价格 > 50)
    COUNT(IF(price <= 50, 1, NULL)) AS low_price_transactions,  -- 低价交易次数(价格 <= 50)
    SUM(quantity * price) / NULLIF(SUM(quantity), 0) AS sales_price,  -- 销售价格
    (SUM(quantity) / SUM(quantity * price)) * 100 AS sales_contribution_rate,  -- 销售贡献率
    COUNT(IF(quantity > 10, 1, NULL)) AS bulk_sales_transactions,  -- 大宗销售交易次数(数量 > 10)
    SUM(IF(timestamp >= (NOW() - INTERVAL 30 DAY), quantity, 0)) AS recent_sales_quantity,  -- 最近30天的销售数量
    SUM(IF(timestamp >= (NOW() - INTERVAL 30 DAY), quantity * price, 0)) AS recent_sales_value,  -- 最近30天的销售额
    AVG(IF(price > 50, price, NULL)) AS avg_high_price,  -- 高价商品的平均价格
    AVG(IF(price <= 50, price, NULL)) AS avg_low_price,  -- 低价商品的平均价格
    SUM(quantity) / NULLIF(COUNT(DISTINCT timestamp), 0) AS avg_quantity_per_day,  -- 每天的平均销售数量
    COUNT(IF(timestamp >= (NOW() - INTERVAL 7 DAY), 1, NULL)) AS recent_transactions,  -- 最近7天的交易次数
    SUM(IF(timestamp >= (NOW() - INTERVAL 7 DAY), quantity, 0)) AS recent_week_sales_quantity,  -- 最近7天的销售数量
    SUM(IF(timestamp >= (NOW() - INTERVAL 7 DAY), quantity * price, 0)) AS recent_week_sales_value,  -- 最近7天的销售额
    SUM(IF(price < 20, quantity, 0)) AS low_price_sales_quantity,  -- 低价销售数量(价格 < 20)
    SUM(IF((price >= 20) AND (price <= 50), quantity, 0)) AS mid_price_sales_quantity,  -- 中价销售数量(20 <= 价格 <= 50)
    SUM(IF(price > 50, quantity, 0)) AS high_price_sales_quantity,  -- 高价销售数量(价格 > 50)
    COUNT(IF(quantity > 1, 1, NULL)) AS multiple_items_transactions,  -- 多件商品交易次数(数量 > 1)
    COUNT(IF(price IS NULL, 1, NULL)) AS missing_price_transactions,  -- 缺失价格的交易次数
    SUM(IF(price IS NOT NULL, quantity * price, 0)) AS sales_with_price,  -- 有价格的销售额
    SUM(IF(price > 100, quantity, 0)) AS high_value_sales_quantity,  -- 高价值销售数量(价格 > 100)
    SUM(IF((price >= 20) AND (price <= 100), quantity, 0)) AS mid_value_sales_quantity,  -- 中价值销售数量(20 <= 价格 <= 100)
    SUM(IF(price < 20, quantity, 0)) AS low_value_sales_quantity,  -- 低价值销售数量(价格 < 20)
    COUNT(IF(quantity > 5, 1, NULL)) AS frequent_buyers,  -- 频繁购买者(数量 > 5)
    SUM(IF(timestamp >= (NOW() - INTERVAL 1 YEAR), quantity, 0)) AS yearly_sales_quantity,  -- 年度销售数量
    SUM(IF(timestamp >= (NOW() - INTERVAL 1 YEAR), quantity * price, 0)) AS yearly_sales_value  -- 年度销售额
FROM sales
GROUP BY product_id  -- 按产品 ID 分组
ORDER BY total_sales DESC;  -- 按总销售额降序排列

查询结果占用资源情况:

10000 rows in set. Elapsed: 2.439 sec. Processed 100.10 million rows, 2.40 GB (41.05 million rows/s., 985.12 MB/s.)
Peak memory usage: 93.66 MiB.

这个查询结果的输出信息包含了几个关键部分,下面逐一解释:

  1. 10000 rows in set

  • 这表示查询结果中返回了 10,000 行数据。这个数字是查询所处理的结果集的行数。
  1. Elapsed: 2.439 sec

  • 这是查询执行的总时间,表示从开始到结束所花费的时间为 2.439 秒。
  1. Processed 100.10 million rows, 2.40 GB

  • 这表示在执行查询时,数据库系统处理了 1 亿 10 万行数据,总共读取了 2.40 GB 的数据。这意味着虽然最终只返回了 10,000 行,但在计算这些结果时,数据库需要扫描大量的数据。
  1. (41.05 million rows/s., 985.12 MB/s.)

  • 这部分提供了处理速度的信息:
    • 985.12 MB/s.:表示数据读取的速度为每秒 985.12 MB。

    • 41.05 million rows/s.:表示查询处理的速度为每秒 4105 万行。

  1. Peak memory usage: 93.66 MiB

  • 这是查询执行过程中使用的最大内存量,表示查询的峰值内存使用为 93.66 MiB。

导出到Excel表格并附加表头

SELECT
    product_id,  -- 产品 ID
    SUM(quantity) AS total_quantity,  -- 总销售数量
    SUM(quantity * price) AS total_sales,  -- 总销售额
    AVG(price) AS average_price,  -- 平均价格
    COUNT(*) AS total_transactions,  -- 总交易次数
    MAX(price) AS max_price,  -- 最高价格
    MIN(price) AS min_price,  -- 最低价格
    SUM(quantity) / NULLIF(COUNT(*), 0) AS avg_quantity_per_transaction_count,  -- 每笔交易的平均数量
    SUM(quantity * price) / NULLIF(SUM(quantity), 0) AS avg_sales_per_unit,  -- 每单位的平均销售额
    SUM(quantity) / NULLIF(COUNT(DISTINCT timestamp), 0) AS avg_daily_sales,  -- 平均每日销售数量
    COUNT(DISTINCT timestamp) AS selling_days,  -- 销售天数
    SUM(quantity * price) / NULLIF(COUNT(DISTINCT timestamp), 0) AS avg_daily_sales_value,  -- 平均每日销售额
    SUM(quantity) / SUM(quantity * price) AS sales_conversion_rate,  -- 销售转化率
    COUNT(IF(price > 50, 1, NULL)) AS high_price_transactions,  -- 高价交易次数(价格 > 50)
    COUNT(IF(price <= 50, 1, NULL)) AS low_price_transactions,  -- 低价交易次数(价格 <= 50)
    SUM(quantity * price) / NULLIF(SUM(quantity), 0) AS sales_price,  -- 销售价格
    (SUM(quantity) / SUM(quantity * price)) * 100 AS sales_contribution_rate,  -- 销售贡献率
    COUNT(IF(quantity > 10, 1, NULL)) AS bulk_sales_transactions,  -- 大宗销售交易次数(数量 > 10)
    SUM(IF(timestamp >= (NOW() - INTERVAL 30 DAY), quantity, 0)) AS recent_sales_quantity,  -- 最近30天的销售数量
    SUM(IF(timestamp >= (NOW() - INTERVAL 30 DAY), quantity * price, 0)) AS recent_sales_value,  -- 最近30天的销售额
    AVG(IF(price > 50, price, NULL)) AS avg_high_price,  -- 高价商品的平均价格
    AVG(IF(price <= 50, price, NULL)) AS avg_low_price,  -- 低价商品的平均价格
    SUM(quantity) / NULLIF(COUNT(DISTINCT timestamp), 0) AS avg_quantity_per_day,  -- 每天的平均销售数量
    COUNT(IF(timestamp >= (NOW() - INTERVAL 7 DAY), 1, NULL)) AS recent_transactions,  -- 最近7天的交易次数
    SUM(IF(timestamp >= (NOW() - INTERVAL 7 DAY), quantity, 0)) AS recent_week_sales_quantity,  -- 最近7天的销售数量
    SUM(IF(timestamp >= (NOW() - INTERVAL 7 DAY), quantity * price, 0)) AS recent_week_sales_value,  -- 最近7天的销售额
    SUM(IF(price < 20, quantity, 0)) AS low_price_sales_quantity,  -- 低价销售数量(价格 < 20)
    SUM(IF((price >= 20) AND (price <= 50), quantity, 0)) AS mid_price_sales_quantity,  -- 中价销售数量(20 <= 价格 <= 50)
    SUM(IF(price > 50, quantity, 0)) AS high_price_sales_quantity,  -- 高价销售数量(价格 > 50)
    COUNT(IF(quantity > 1, 1, NULL)) AS multiple_items_transactions,  -- 多件商品交易次数(数量 > 1)
    COUNT(IF(price IS NULL, 1, NULL)) AS missing_price_transactions,  -- 缺失价格的交易次数
    SUM(IF(price IS NOT NULL, quantity * price, 0)) AS sales_with_price,  -- 有价格的销售额
    SUM(IF(price > 100, quantity, 0)) AS high_value_sales_quantity,  -- 高价值销售数量(价格 > 100)
    SUM(IF((price >= 20) AND (price <= 100), quantity, 0)) AS mid_value_sales_quantity,  -- 中价值销售数量(20 <= 价格 <= 100)
    SUM(IF(price < 20, quantity, 0)) AS low_value_sales_quantity,  -- 低价值销售数量(价格 < 20)
    COUNT(IF(quantity > 5, 1, NULL)) AS frequent_buyers,  -- 频繁购买者(数量 > 5)
    SUM(IF(timestamp >= (NOW() - INTERVAL 1 YEAR), quantity, 0)) AS yearly_sales_quantity,  -- 年度销售数量
    SUM(IF(timestamp >= (NOW() - INTERVAL 1 YEAR), quantity * price, 0)) AS yearly_sales_value,  -- 年度销售额
    AVG(IF(price IS NOT NULL, price, NULL)) AS avg_price,  -- 平均价格(排除 NULL)
    COUNT(DISTINCT customer_id) AS unique_customers,  -- 唯一客户数量
    COUNT(IF(quantity = 0, 1, NULL)) AS zero_quantity_sales,  -- 销售数量为零的交易次数
    SUM(IF(price IS NOT NULL AND quantity > 0, quantity * price, 0)) AS valid_sales_value  -- 有效销售额(价格不为 NULL 且数量 > 0)
FROM sales
GROUP BY product_id  -- 按产品 ID 分组
ORDER BY total_sales DESC  -- 按总销售额降序排列
INTO OUTFILE '/test1.csv'  -- 输出到 CSV 文件
FORMAT CSVWithNames;  -- CSV 格式包含列名

然后下载到Windows系统打开即可

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2164130.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

性能测试1初步使用Jmeter

当你看到这边文章的时候&#xff0c;详细你已经知道啥是性能测试&#xff0c;以及也听说过Jmeter了&#xff0c;所以不过多介绍&#xff0c;这里&#xff0c;只是帮助你快速的使用Jmeter来测试接口。 1获取安装包 官网下载地址&#xff1a;https://jmeter.apache.org/downloa…

力扣19 删除链表的倒数第N个节点 Java版本

文章目录 题目描述代码 题目描述 给你一个链表&#xff0c;删除链表的倒数第 n 个结点&#xff0c;并且返回链表的头结点。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5], n 2 输出&#xff1a;[1,2,3,5] 示例 2&#xff1a; 输入&#xff1a;head [1], n 1 …

erlang学习:Linux命令学习4

顺序控制语句学习 if&#xff0c;else对文件操作 判断一个文件夹是否存在&#xff0c;如果存在则进行删除&#xff0c;如果不存在则创建该文件夹&#xff0c;并复制一份该脚本后&#xff0c;删除该脚本 if [ -d "/erlangtest/testdir"]; then echo "删除文件夹…

数字化转型:国内证书哪个更有用

探讨数字化转型&#xff0c;有哪些国内证书推荐&#xff1f;让我们一起来了解一下。 软考-系统集成项目管理工程师(中项)/信息系统项目管理师(高项)&#xff1a;由人社部和工信部联合颁发&#xff0c;紧密贴合国内IT领域的项目管理实际需求。 这两个软考科目没有考试门槛限制…

AI 文生图快速入门教程:让 Stable Diffusion 更易于上手

Stable Diffusion 是一个强大的 AI 图像生成工具&#xff0c;但它可能会消耗大量资源。在本指南中&#xff0c;我们将学习如何使用 AUTOMATIC1111 的 Stable Diffusion WebUI 来设置它。同时&#xff0c;我们将在 DigitalOcean GPU Droplet 云服务器上运行它&#xff0c;通过 H…

python爬虫:从12306网站获取火车站信息

代码逻辑 初始化 (init 方法)&#xff1a; 设置请求头信息。设置车站版本号。 同步车站信息 (synchronization 方法)&#xff1a; 发送GET请求获取车站信息。返回服务器响应的文本。 提取信息 (extract 方法)&#xff1a; 从服务器响应中提取车站信息字符串。去掉字符串末尾的…

钰泰-ETA6027限流开关IC

描述 ETA6027 是一种负载开关&#xff0c;可为可能遇到大电流条件的系统和负载提供全面保护。ETA6027 提供 70mΩ 限流开关&#xff0c;可在 2.1-6V 的输入电压范围内工作。电流限制可通过精密电阻器进行外部编程&#xff0c;范围为 75mA 至 2.2A。开关控制由能够直接与低电压…

国庆节前超市现场运营重点工作

节日期间的营运现场工作&#xff0c;很容易由于工作量突然加大&#xff0c;造成很多细化工作不能很好地具体落实&#xff0c;完善现场工作的诸多细节&#xff0c;对于提升业绩会有很好的效果。其中前台需要以冲业绩的方式来完成&#xff0c;后台需要运用精细化的方式来对待。一…

安卓 shape 的使用

在Android开发中&#xff0c;<shape>元素是一个XML资源&#xff0c;用于定义形状&#xff0c;如矩形、圆形、椭圆形、线条等。这些形状可以用于多种场景&#xff0c;比如作为按钮的背景、视图边框或者列表项的分隔线等。<shape>元素位于drawable资源文件夹&#xf…

移动化社交:Facebook的移动战略解析

在移动互联网时代&#xff0c;社交媒体的使用方式和用户习惯发生了显著变化。作为全球最大的社交网络平台之一&#xff0c;Facebook在移动化战略上进行了深远的布局&#xff0c;以适应这一趋势并保持其在市场中的竞争力。本文将探讨Facebook的移动战略及其背后的影响。 移动优先…

云课五分钟-Arduino wokwi和步进电机实验报告快速撰写

wokwi 程序 #include <AccelStepper.h> // Define a stepper and the pins it will use AccelStepper stepper; // Defaults to AccelStepper::FULL4WIRE (4 pins) on 2, 3, 4, 5 // This defines the analog input pin for reading the control voltage // Tested wit…

HarmonyOS鸿蒙开发实战(5.0)自定义安全键盘场景实践

鸿蒙HarmonyOS开发实战往期必看文章&#xff1a;&#xff08;持续更新......&#xff09; HarmonyOS NEXT应用开发性能实践总结&#xff08;持续更新......&#xff09; HarmonyOS NEXT应用开发案例实践总结合集&#xff08;持续更新......&#xff09; 一分钟了解”纯血版&…

编译原理3——词法分析

3.1词法分析器的作用 词法分析是编译的第一阶段。词法分析器的主要任务是读入源程序的输入字符、将它们组成词素&#xff0c;生成并输出一个词法单元序列&#xff0c;每个词法单元对应于一个词素。 但在这个过程中&#xff0c;词法分析器还要和语法分析器进行交互。交互&…

计算机出现msvcp140.dll丢失的6种解决方法,亲测有效

在计算机使用过程中&#xff0c;我们经常会遇到一些错误提示&#xff0c;其中之一就是“msvcp140.dll丢失”。这个错误通常会导致某些应用程序无法正常运行&#xff0c;给用户带来困扰。本文将总结6种解决msvcp140.dll丢失的方法&#xff0c;帮助大家轻松解决这个问题。 一&…

1、软件测试的基础概念(1)

文章目录 一、软件测试1、软件测试&#xff08;Software Testing&#xff09;2、缺陷&#xff08;Defeat&#xff09;3、测试用例&#xff08;Test Case&#xff09;4、测试金字塔5、测试策略6、测试左移和测试右移7、质量度量 二、软件的测试分类1、单元测试2、集成测试3、系统…

2024中国新科技100强名单出炉!MIAOYUN荣获“2024云原生领航企业奖”

当前&#xff0c;新一轮科技革命和产业变革加速演进&#xff0c;只有加强颠覆性科技创新&#xff0c;才能占领科技创新的制高点&#xff0c;为发展新质生产力注入强大动能&#xff0c;不断塑造高质量发展竞争优势。近日&#xff0c;2024中国新科技100强金i奖评选名单出炉&#…

Thingsboard规则链:fetch device credentials节点详解

引言 源码剖析 应用场景与案例 结语 ThingsBoard从入门到实战课程&#xff0c;深入透析底层原理&#xff0c;快速搭建自己的IOT平台_哔哩哔哩_bilibiliThingsBoard从入门到实战课程&#xff0c;深入透析底层原理&#xff0c;快速搭建自己的IOT平台共计12条视频&#xff0c;包…

π122M31 双通道数字隔离器,工业控制领域的得力助手

π122M31 双通道数字隔离器 CAN通信隔离兼容ADuM7241ARZ电路简单、稳定性更高&#xff0c;具有出色的性能特征和可靠性&#xff0c;整体性能优于光耦和基于其他原理的数字隔离器产品。 产品传输通道间彼此独立&#xff0c;可实现多种传输方向的配置&#xff0c;可实现 5.0kVrms…

Bugku 渗透测试1

描  述: 甲公司邀请你对他们公司进行网络安全测试&#xff0c;但是甲公司只给了一个官网链接你能打到他们内网吗&#xff1f; 打开靶场地址 1、场景1 查看网站源码&#xff0c;查看最下面&#xff0c;得到flag。 2、场景2 根据场景1提示&#xff0c;下个flag网站管理员才能…

SelMatch:最新数据集蒸馏,仅用5%训练数据也是可以的 | ICML‘24

数据集蒸馏旨在从大型数据集中合成每类&#xff08;IPC&#xff09;少量图像&#xff0c;以在最小性能损失的情况下近似完整数据集训练。尽管在非常小的IPC范围内有效&#xff0c;但随着IPC增加&#xff0c;许多蒸馏方法变得不太有效甚至性能不如随机样本选择。论文对各种IPC范…