ClickHouse 是俄罗斯的 Yandex 于 2016 年开源的列式存储数据库(DBMS),使用 C++
语言编写,主要用于在线分析处理查询(OLAP),能够使用 SQL 查询实时生成分析数据报
告。
官网:https://clickhouse.com/docs/zh
列式存储优点:
几乎覆盖了标准 SQL 的大部分语法,包括 DDL 和 DML,以及配套的各种函数,用户管理及权限管理,数据的备份与恢复。
ClickHouse 和 MySQL 类似,把表级的存储引擎插件化,根据表的不同需求可以设定不同的存储引擎。目前包括合并树、日志、接口和其他四大类 20 多种引擎。
ClickHouse采用类LSM Tree的结构,数据写入后定期在后台Compaction。通过类LSM tree的结构,ClickHouse 在数据导入时全部是顺序 append 写,写入后数据段不可更改,在后台compaction 时也是多个段 merge sort 后顺序写回磁盘。顺序写的特性,充分利用了磁盘的吞吐能力,即便在 HDD 上也有着优异的写入性能。
官方公开 benchmark 测试显示能够达到 50MB-200MB/s 的写入吞吐能力,按照每行100Byte 估算,大约相当于 50W-200W 条/s 的写入速度。
ClickHouse 将数据划分为多个 partition,每个 partition 再进一步划分为多个 indexgranularity(索引粒度),然后通过多个CPU核心分别处理其中的一部分来实现并行数据处理。在这种设计下,单条 Query 就能利用整机所有 CPU。极致的并行处理能力,极大的降低了查询延时。
所以,ClickHouse 即使对于大量数据的查询也能够化整为零平行处理。但是有一个弊端就是对于单条查询使用多 cpu,就不利于同时并发多条查询。所以对于高 qps 的查询业务,ClickHouse 并不是强项。
单表查询
关联查询
结论: ClickHouse 像很多 OLAP 数据库一样,单表查询速度由于关联查询,而且 ClickHouse的两者差距更为明显。
sudo vim /etc/security/limits.conf 末尾增加
* soft nofile 65536
* hard nofile 65536
* soft nproc 131072
* hard nproc 131072
修改/etc/selinux/config 中的 SELINUX=disabled
SELINUX=disabled
sudo vim /etc/clickhouse-server/config.xml
::</listen_host> 的注释打开
固定长度的整型,包括有符号整型或无符号整型。
使用场景: 个数、数量、也可以存储型 id 。
建议尽可能以整数形式存储数据。例如,将固定精度的数字转换为整数值,如时间用毫秒为单位表示,因为浮点型进行计算时可能引起四舍五入的误差。
没有单独的类型来存储布尔值。可以使用 UInt8 类型,取值限制为 0 或 1。
有符号的浮点数,可在加、减和乘法运算过程中保持精度。对于除法,最低有效数字会被丢弃(不舍入)。
有三种声明: s 标识小数位
使用场景: 一般金额字段、汇率、利率等字段为了保证小数点精度,都使用 Decimal进行存储。
使用场景:名称、文字描述、字符型编码。 固定长度的可以保存一些定长的内容,比如一些编码,性别等但是考虑到一定的变化风险,带来收益不够明显,所以定长字符串使用意义有限。
CREATE TABLE t_enum
(
x Enum8('hello' = 1, 'world' = 2)
)
ENGINE = TinyLog;
使用场景:对一些状态、类型的字段算是一种空间优化,也算是一种数据约束。但是实际使用中往往因为一些数据内容的变化增加一定的维护成本,甚至是数据丢失问题。所以谨慎使用。
目前 ClickHouse 有三种时间类型
T 可以是任意类型,包含数组类型。 但不推荐使用多维数组,ClickHouse 对多维数组的支持有限。
表引擎是 ClickHouse 的一大特色。可以说, 表引擎决定了如何存储表的数据。包括:
表引擎的使用方式就是必须显式在创建表时定义该表使用的引擎,以及引擎使用的相关参数。
特别注意:引擎的名称大小写敏感
以列文件的形式保存在磁盘上,不支持索引,没有并发控制。一般保存少量数据的小表,生产环境上作用有限。可以用于平时练习测试用。
内存引擎,数据以未压缩的原始形式直接保存在内存当中,服务器重启数据就会消失。读写操作不会相互阻塞,不支持索引。简单查询下有非常非常高的性能表现(超过 10G/s)。
一般用到它的地方不多,除了用来测试,就是在需要非常高的性能,同时数据量又不太大(上限大概 1 亿行)的场景。
ClickHouse 中最强大的表引擎当属 MergeTree(合并树)引擎及该系列(*MergeTree)中的其他引擎,支持索引和分区,地位可以相当于 innodb 之于 Mysql。 而且基于 MergeTree,还衍生除了很多小弟,也是非常有特色的引擎。
create table t_order_mt(
id UInt32,
sku_id String,
total_amount Decimal(16,2),
create_time Datetime
) engine =MergeTree
partition by toYYYYMMDD(create_time)
primary key (id)
order by (id,sku_id);
optimize table xxxx final;
稀疏索引:
稀疏索引的好处就是可以用很少的索引数据,定位更多的数据,代价就是只能定位到索引粒度的第一行,然后再进行进行一点扫描。
目前在 ClickHouse 的官网上二级索引的功能在 v20.1.2.4 之前是被标注为实验性的,在这个版本之后默认是开启的。
老版本 使用二级索引前需要增加设置
是否允许使用实验性的二级索引(v20.1.2.4 开始,这个参数已被删除,默认开启)
set allow_experimental_data_skipping_indices=1;
create table t_order_mt2(
id UInt32,
sku_id String,
total_amount Decimal(16,2),
create_time Datetime,
INDEX a total_amount TYPE minmax GRANULARITY 5
) engine =MergeTree
partition by toYYYYMMDD(create_time)
primary key (id)
order by (id, sku_id);
其中 GRANULARITY N 是设定二级索引对于一级索引粒度的粒度。
TTL 即 Time To Live,MergeTree 提供了可以管理数据表或者列的生命周期的功能。
total_amount Decimal(16,2) TTL create_time+interval 10 SECOND,
下面的这条语句是数据会在 create_time 之后 10 秒丢失
alter table t_order_mt3 MODIFY TTL create_time + INTERVAL 10 SECOND;
涉及判断的字段必须是 Date 或者 Datetime 类型,推荐使用分区的日期字段。
能够使用的时间周期:
ReplacingMergeTree 是 MergeTree 的一个变种,它存储特性完全继承 MergeTree,只是多了一个去重的功能。 尽管 MergeTree 可以设置主键,但是 primary key 其实没有唯一约束的功能。如果你想处理掉重复的数据,可以借助这个 ReplacingMergeTree。
案例演示
create table t_order_rmt(
id UInt32,
sku_id String,
total_amount Decimal(16,2) ,
create_time Datetime
) engine =ReplacingMergeTree(create_time)
partition by toYYYYMMDD(create_time)
primary key (id)
order by (id, sku_id);
ReplacingMergeTree() 填入的参数为版本字段,重复数据保留版本字段值最大的。
如果不填版本字段,默认按照插入顺序保留最后一条。
结论:
对于不查询明细,只关心以维度进行汇总聚合结果的场景。如果只使用普通的MergeTree的话,无论是存储空间的开销,还是查询时临时聚合的开销都比较大。
ClickHouse 为了这种场景,提供了一种能够“预聚合”的引擎SummingMergeTree
案例演示
create table t_order_smt(
id UInt32,
sku_id String,
total_amount Decimal(16,2) ,
create_time Datetime
) engine =SummingMergeTree(total_amount)
partition by toYYYYMMDD(create_time)
primary key (id)
order by (id,sku_id );
结论
开发建议
设计聚合表的话,唯一键值、流水号可以去掉,所有字段全部是维度、度量或者时间戳。
问题:
能不能直接执行以下 SQL 得到汇总值
select total_amount from XXX where province_name=’’ and create_date=’xxx’
不行,可能会包含一些还没来得及聚合的临时明细
如果要是获取汇总值,还是需要使用 sum 进行聚合,这样效率会有一定的提高,但本身 ClickHouse 是列式存储的,效率提升有限,不会特别明显。
select sum(total_amount) from province_name=’’ and create_date=‘xxx’
https://clickhouse.com/docs/zh/engines/table-engines
基本SQL操作参考官方文档:https://clickhouse.com/docs/zh/sql-reference
删除操作
alter table t_order_smt delete where sku_id ='sku_001';
修改操作
alter table t_order_smt update total_amount=toDecimal32(2000.00,2) where id = 102;
由于操作比较“重”,所以 Mutation 语句分两步执行,同步执行的部分其实只是进行新增数据新增分区和并把旧分区打上逻辑上的失效标记。直到触发分区合并的时候,才会删除旧数据释放磁盘空间,一般不会开放这样的功能给用户,由管理员完成。
ClickHouse 基本上与标准 SQL 差别不大
案例:with rollup - 从右至左去掉维度进行小计
select id , sku_id,sum(total_amount) from t_order_mt group by
id,sku_id with rollup;
案例:with cube : 从右至左去掉维度进行小计,再从左至右去掉维度进行小计
select id , sku_id,sum(total_amount) from t_order_mt group by
id,sku_id with cube;
select id , sku_id,sum(total_amount) from t_order_mt group by
id,sku_id with totals;
alter table tableName add column newcolname String after col1;
alter table tableName modify column newcolname String;
alter table tableName drop column newcolname;
clickhouse-client --query "select * from t_order_mt where
create_time='2020-06-01 12:00:00'" --format CSVWithNames>
/opt/module/data/rs1.csv
副本的目的主要是保障数据的高可用性,即使一台 ClickHouse 节点宕机,那么也可以从其他服务器获得相同的数据。
1、/etc/clickhouse-server/config.d 目录下创建一个名为 metrika.xml的配置文件:注:也可以不创建外部文件,直接在 config.xml 中指定
<yandex>
<zookeeper-servers>
<node index="1">
<host>hadoop地址host>
<port>2181port>
node>
<node index="2">
<host>hadoop地址host>
<port>2181port>
node>
<node index="3">
<host>hadoop地址host>
<port>2181port>
node>
zookeeper-servers>
yandex>
2、/etc/clickhouse-server/config.xml 中增加
<zookeeper incl="zookeeper-servers" optional="true" />
<include_from>/etc/clickhouse-server/config.d/metrika.xmlinclude_from>
3、重启服务
4、其他说明
create table t_order_rep2 (
id UInt32,
sku_id String,
total_amount Decimal(16,2),
create_time Datetime
) engine =ReplicatedMergeTree('/clickhouse/table/01/t_order_rep','rep_102')
partition by toYYYYMMDD(create_time)
primary key (id)
order by (id,sku_id);
create table t_order_rep2 (
id UInt32,
sku_id String,
total_amount Decimal(16,2),
create_time Datetime
) engine =ReplicatedMergeTree('/clickhouse/table/01/t_order_rep','rep_103')
partition by toYYYYMMDD(create_time)
primary key (id)
order by (id,sku_id);
参数解释 ReplicatedMergeTree
注意:ClickHouse 的集群是表级别的,实际企业中,大部分做了高可用,但是没有用分片,避免降低查询性能以及操作集群的复杂性。
配置的位置还是在之前的/etc/clickhouse-server/config.d/metrika.xml,内容如下:
注:也可以不创建外部文件,直接在 config.xml 的
<yandex>
<remote_servers>
<gmall_cluster>
<shard>
<internal_replication>trueinternal_replication>
<replica>
<host>hadoop101host>
<port>9000port>
replica>
<replica>
<host>hadoop102host>
<port>9000port>
replica>
shard>
<shard>
<internal_replication>trueinternal_replication>
<replica>
<host>hadoop103host>
<port>9000port>
replica>
<replica>
<host>hadoop104host>
<port>9000port>
replica>
shard>
<shard>
<internal_replication>trueinternal_replication>
<replica>
<host>hadoop105host>
<port>9000port>
replica>
<replica>
<host>hadoop106host>
<port>9000port>
replica>
shard>
gmall_cluster>
remote_servers>
yandex>
create table st_order_mt_all2 on cluster gmall_cluster
(
id UInt32,
sku_id String,
total_amount Decimal(16,2),
create_time Datetime
)engine = Distributed(gmall_cluster,default,st_order_mt,hiveHash(sku_id));
参数含义:
在 clickhouse 20.6 版本之前要查看 SQL 语句的执行计划需要设置日志级别为 trace 才能可以看到,并且只能真正执行 sql,在执行日志里面查看。在 20.6 版本引入了原生的执行计划的语法。在 20.6.3 版本成为正式版本的功能。
EXPLAIN [AST | SYNTAX | PLAN | PIPELINE] [setting = value, ...]
SELECT ... [FORMAT ...]
注: PLAN 和 PIPELINE 还可以进行额外的显示设置,如上参数所示。
可以再安装一个 20.6 以上版本,或者直接在官网的在线 demo,选择高版本进行测试。
官网示例集:https://clickhouse.com/docs/zh/getting-started/example-datasets
查看 PLAIN - 简单查询
explain plan select arrayJoin([1,2,3,null,null]);
查看PLAIN - 复杂SQL
explain select database,table,count(1) cnt from system.parts where
database in ('datasets','system') group by database,table order by
database,cnt desc limit 2 by database;
查看PLAIN - 打开全部的参数的执行计划
EXPLAIN header=1, actions=1,description=1 SELECT number from
system.numbers limit 10;
AST 语法树
EXPLAIN AST SELECT number from system.numbers limit 10;
SYNTAX 语法优化
//先做一次查询
SELECT number = 1 ? 'hello' : (number = 2 ? 'world' : 'atguigu') FROM numbers(10);
//查看语法优化
EXPLAIN SYNTAX SELECT number = 1 ? 'hello' : (number = 2 ? 'world' :
'atguigu') FROM numbers(10);
//开启三元运算符优化
SET optimize_if_chain_to_multiif = 1;
//再次查看语法优化
EXPLAIN SYNTAX SELECT number = 1 ? 'hello' : (number = 2 ? 'world' :
'atguigu') FROM numbers(10);
//返回优化后的语句
SELECT multiIf(number = 1, \'hello\', number = 2, \'world\', \'xyz\')
FROM numbers(10)
查看 PIPELINE
EXPLAIN PIPELINE SELECT sum(number) FROM numbers_mt(100000) GROUP BY
number % 20;
//打开其他参数
EXPLAIN PIPELINE header=1,graph=1 SELECT sum(number) FROM
numbers_mt(10000) GROUP BY number%20;
clickhouse-client -h 主机名 --send_logs_level=trace <<< "sql" > /dev/null
其中,send_logs_level 参数指定日志等级为 trace,<<<将 SQL 语句重定向至 clickhouse-client 进行查询,> /dev/null 将查询结果重定向到空设备吞掉,以便观察日志。
注意:
create table t_type2(
id UInt32,
sku_id String,
total_amount Decimal(16,2) ,
create_time Int32
) engine =ReplacingMergeTree(create_time)
partition by toYYYYMMDD(toDate(create_time)) –-需要转换一次,否则报错
primary key (id)
order by (id, sku_id);
官方已经指出 Nullable 类型几乎总是会拖累性能,因为存储 Nullable 列时需要创建一个额外的文件来存储 NULL 的标记,并且 Nullable 列无法被索引。因此除非极特殊情况,应直接使用字段默认值表示空,或者自行指定一个在业务中无意义的值(例如用-1 表示没有商品ID)。
CREATE TABLE t_null(x Int8, y Nullable(Int8)) ENGINE TinyLog;
INSERT INTO t_null VALUES (1, NULL), (2, 3);
SELECT x + y FROM t_null;
查看存储的文件:
……
PARTITION BY toYYYYMM(EventDate)
ORDER BY (CounterID, EventDate, intHash32(UserID))
……
……
PARTITION BY toYYYYMM(StartDate)
ORDER BY (CounterID, StartDate, intHash32(UserID), VisitID)
……
1. Code: 252, e.displayText() = DB::Exception: Too many parts(304).
Merges are processing significantly slower than inserts
2. Code: 241, e.displayText() = DB::Exception: Memory limit (for query)
exceeded:would use 9.37 GiB (attempt to allocate chunk of 301989888
bytes), maximum: 9.31 Gi
处理方式:
“ Too many parts 处理 ” :使用 WAL 预写日志,提高写入性能。
in_memory_parts_enable_wal 默认为 true
在服务器内存充裕的情况下增加内存配额,一般通过 max_memory_usage 来实现
在服务器内存不充裕的情况下,建议将超出部分内容分配到系统硬盘上,但会降低执行速度,一般通过 max_bytes_before_external_group_by、max_bytes_before_external_sort 参数来实现。
config.xml 或 users.xml 中, 基本上都在 users.xml
ClickHouse 不支持设置多数据目录,为了提升数据 io 性能,可以挂载虚拟券组,一个券组绑定多块物理磁盘提升读写性能,多数据查询场景 SSD 会比普通机械硬盘快 2-3 倍。
下面语句子查询中有两个重复的 id 字段,会被去重:
EXPLAIN SYNTAX
SELECT a.UserID, b.VisitID, a.URL, b.UserID
FROM hits_v1 AS a
LEFT JOIN (
SELECT UserID, UserID as HaHa, VisitID
FROM visits_v1) AS b
USING (UserID)
limit 3;
//返回优化语句:
SELECT UserID, VisitID, URL, b.UserID
FROM hits_v1 AS a
ALL LEFT JOIN
(
SELECT UserID, VisitID
FROM visits_v1
) AS b USING (UserID)
LIMIT 3
EXPLAIN SYNTAX
SELECT sum(UserID * 2) FROM visits_v1
//返回优化后的语句
SELECT sum(UserID) * 2 FROM visits_v1
EXPLAIN SYNTAX
SELECT
sum(UserID * 2),
max(VisitID),
max(UserID)
FROM visits_v1
GROUP BY UserID
//返回优化后的语句
SELECT
sum(UserID) * 2,
max(VisitID),
UserID
FROM visits_v1
GROUP BY UserID
EXPLAIN SYNTAX
SELECT *
FROM visits_v1
ORDER BY
UserID ASC,
UserID ASC,
VisitID ASC,
VisitID ASC
//返回优化后的语句:
select
……
FROM visits_v1
ORDER BY
UserID ASC,
VisitID ASC
EXPLAIN SYNTAX
SELECT *
FROM visits_v1
LIMIT 3 BY
VisitID,
VisitID
LIMIT 10
//返回优化后的语句:
select
……
FROM visits_v1
LIMIT 3 BY VisitID
LIMIT 10
EXPLAIN SYNTAX
SELECT
a.UserID,
a.UserID,
b.VisitID,
a.URL,
b.UserID
FROM hits_v1 AS a
LEFT JOIN visits_v1 AS b USING (UserID, UserID)
//返回优化后的语句:
SELECT
UserID,
UserID,
VisitID,
URL,
b.UserID
FROM hits_v1 AS a
ALL LEFT JOIN visits_v1 AS b USING (UserID)
EXPLAIN SYNTAX
WITH
(
SELECT sum(bytes)
FROM system.parts
WHERE active
) AS total_disk_usage
SELECT
(sum(bytes) / total_disk_usage) * 100 AS table_disk_usage,
table
FROM system.parts
GROUP BY table
ORDER BY table_disk_usage DESC
LIMIT 10;
//返回优化后的语句:
WITH CAST(0, \'UInt64\') AS total_disk_usage
SELECT
(sum(bytes) / total_disk_usage) * 100 AS table_disk_usage,
table
FROM system.parts
GROUP BY table
ORDER BY table_disk_usage DESC
LIMIT 10
EXPLAIN SYNTAX
SELECT number = 1 ? 'hello' : (number = 2 ? 'world' : 'atguigu')
FROM numbers(10)
settings optimize_if_chain_to_multiif = 1;
//返回优化后的语句:
SELECT multiIf(number = 1, \'hello\', number = 2, \'world\', \'atguigu\')
FROM numbers(10)
SETTINGS optimize_if_chain_to_multiif = 1
默认情况, where 会自动优化成 prewhere,但是某些场景即使开启优化,也不会自动转换成 prewhere,需要手动指定 prewhere:
SELECT Title,count(*) AS PageViews
FROM hits_v1
SAMPLE 0.1 #代表采样 10%的数据,也可以是具体的条数
WHERE CounterID =57
GROUP BY Title
ORDER BY PageViews DESC LIMIT 1000
采样修饰符只有在 MergeTree engine 表中才有效,且在创建表时需要指定采样策略。
反例:
select * from datasets.hits_v1;
正例:
select WatchID,
JavaEnable,
Title,
GoodEvent,
EventTime,
EventDate,
CounterID,
ClientIP,
ClientIP6,
RegionID,
UserID
from datasets.hits_v1;
select WatchID,
JavaEnable,
Title,
GoodEvent,
EventTime,
EventDate,
CounterID,
ClientIP,
ClientIP6,
RegionID,
UserID
from datasets.hits_v1
where EventDate='2014-03-23';
#正例:
SELECT UserID,Age
FROM hits_v1
WHERE CounterID=57
ORDER BY Age DESC LIMIT 1000
#反例:
SELECT UserID,Age
FROM hits_v1
ORDER BY Age DESC
反例:
SELECT Income,Age,Income/Age as IncRate FROM datasets.hits_v1;
正例:
拿到 Income 和 Age 后,考虑在前端进行处理,或者在表中构造实际字段进行额外存储
SELECT Income,Age FROM datasets.hits_v1;
反例:
select count(distinct rand()) from hits_v1;
正例:
SELECT uniqCombined(rand()) from datasets.hits_v1
insert into hits_v2
select a.* from hits_v1 a where a. CounterID in (select CounterID from
visits_v1);
#反例:使用 join
insert into table hits_v2
select a.* from hits_v1 a left join visits_v1 b on a. CounterID=b.
CounterID;
查询 CK 手册发现,即便对数据一致性支持最好的 Mergetree,也只是保证 最终一致性
我们在使用 ReplacingMergeTree、SummingMergeTree 这类表引擎的时候,会出现短暂
数据不一致的情况。
在某些对一致性非常敏感的场景,通常有以下几种解决方案。
在写入数据后,立刻执行 OPTIMIZE 强制触发新写入分区的合并动作。
OPTIMIZE TABLE test_a FINAL;
语法:OPTIMIZE TABLE [db.]name [ON CLUSTER cluster] [PARTITION partition |
PARTITION ID 'partition_id'] [FINAL] [DEDUPLICATE [BY expression]]
SELECT
user_id ,
argMax(score, create_time) AS score,
argMax(deleted, create_time) AS deleted,
max(create_time) AS ctime
FROM test_a
GROUP BY user_id
HAVING deleted = 0;
函数说明:
当我们更新数据时,会写入一行新的数据,例如上面语句中,通过查询最大的
create_time 得到修改后的 score 字段值。
普通查询:
select * from visits_v1 WHERE StartDate = '2014-03-17' limit 100 settings
max_threads = 2;
FINAL查询:
select * from visits_v1 final WHERE StartDate = '2014-03-17' limit 100
settings max_final_threads = 2;
普通视图不保存数据,保存的仅仅是查询语句,查询的时候还是从原表读取数据,可以
将普通视图理解为是个子查询。 物化视图则是把查询的结果根据相应的引擎存入到了磁盘
或内存中,对数据重新进行了组织,你可以理解物化视图是完全的一张新表。
其中, _version 用作 ReplacingMergeTree 的 ver 版本参数,每当监听到 insert、update
和 delete 事件时,在 databse 内全局自增。而 _sign 则用于标记是否被删除,取值 1 或者 -1。
目前 MaterializeMySQL 支持如下几种 binlog 事件:
DDL 查询
数据复制
MaterializeMySQL 不支持直接插入、删除和更新查询,而是将 DDL 语句进行相应转换:
SELECT 查询
索引转换
问题:
使用分布式 ddl 执行命令 create table on cluster xxxx 某个节点上没有创建
表,但是 client 返回正常,查看日志有如下报错。
xxx.xxx: Retrying createReplica(), because some other replicas
were created at the same time
解决办法:
重启该不执行的节点。
问题
由于某个数据节点副本异常,导致两数据副本表不一致,某个数据副本缺少表,需要将两个数据副本调整一致。
解决办法
问题
解决办法
问题
Can’t get data for node /clickhouse/tables/01-
02/xxxxx/xxxxxxx/replicas/xxx/metadata: node doesn’t exist (No node):
Cannot attach table xxxxxxx
解决办法
问题
Replica /clickhouse/tables/01-03/xxxxxx/xxx/replicas/xxx already exists..
解决办法
问题
现象
Code: 159. DB::Exception: Received from localhost:9000. DB::Exception:
Watching task /clickhouse/task_queue/ddl/query-0000565925 is executing
longer than distributed_ddl_task_timeout (=180) seconds. There are 1
unfinished hosts (0 of them are currently active), they are going to
execute the query in background.
解决办法
https://help.aliyun.com/document_detail/162815.html?spm=a2c4g.11186623.6.652.312e79bd17U8IO