将Postgresql和Elasticsearch进行数据同步以加速查询

(本文内容适用于elasticsearch7.x,postgresql11)
受命要求优化一个1500w行的表的查询优化,该表中的数据按天update,所以尽管每天vacuum,但是因为空间并没有实际被释放,查询仍然很慢,这下靓仔怎么办?

一开始想到的方法是进行表分区,按日分区,同时修改数据格式减少update,但是一是附加的代码改动过多,二是实际跑了几个测试数据优化效果只有三分之一。不爽啊,这不是一次合格的优化。

然后想起以前做游戏分发业务的时候,把所有接口数据弄成现成的格式直接从redis进行返回,数据的统计,格式化等等过程在django的signal过程内进行。我现在的项目算是个flask项目,虽然并没使用任何orm,但是这也为我提供了一种思路:把postgresql里的数据用某种方式同步到redis或者类似的玩意儿里。最终经过一系列的调研,选定了elasticsearch。
这段时间里主要靠以下几个文档作为出发点(以下内容适用于elasticsearch2.x):

https://www.jianshu.com/p/629f698a7c58
https://yq.aliyun.com/articles/56824#modal-login

针对pg11/es7 上述过程已经有些不使用,比如pg-es-fdw已经被归档,而它并不兼容于es7,需要使用其他人fork并迭代的版本:
postgres-elasticsearch-fdw (https://github.com/matthewfranglen/postgres-elasticsearch-fdw)
而它的依赖urllib3在python2(必须大于2.7才能安装)环境里安装的时候如果使用setup.py安装则会因为setuptool版本的问题无法安装,我尝试了这个方法并且提交了issue和pr,最后被拒了,大概是因为我的个例,很蠢,setuptool的迷之配置(https://github.com/urllib3/urllib3/issues/1753),但是我在如此修改安装文件之后成功地安装了相关的包。

正式开始:

0:环境:CentOS Linux release 7.6.1810 (Core)
首先需要安装:
1、PostgreSQL我的版本是11
2、elasticsearch我用的7.4 按照官网的攻略安装就可以
3、安装multicorn:
https://github.com/Kozea/Multicorn
在centos里安装不需要上边链接里花里胡哨的操作,那个是在mac上安装的
4、在pg里新建extension: multicorn,在你想要优化的表所在的schema里创建:
create extension multicorn;
5、安装postgresql插件postgresql-elasticsearch-fdw,上边链接里的pg-es-fw不适用用es7
https://github.com/matthewfranglen/postgres-elasticsearch-fdw

6、在你想要优化的表所在的schema里创建foreign server:

CREATE SERVER multicorn_es FOREIGN DATA WRAPPER multicorn
OPTIONS (
  wrapper 'pg_es_fdw.ElasticsearchFDW'
);

7、如果是新表,或者你打算试试,可以先建个测试表:


                
<think>好的,用户问的是如何优化一百万条数据来加快查询速度。我需要先理清楚可能的优化方向。首先,一百万条数据不算特别大,但如果没有合适的优化,查询可能会变慢。 用户可能是开发人员或者数据库管理员,他们遇到了查询性能的问题,想要找到解决方法。他们可能对数据库优化有一定了解,但需要更具体的指导。深层需求可能是希望全面了解优化的各个方面,而不仅仅是索引之类的常见方法。 接下来,我应该考虑多个层面的优化策略。首先是数据库设计方面,比如表结构是否合理,有没有正规化或反正规化,字段类型是否合适。然后是索引优化,包括选择合适的索引类型,避免过多索引,使用覆盖索引等。 查询语句本身的优化也很重要,比如避免SELECT *,优化JOIN操作WHERE子句。分区分表也是常用的方法,特别是针对大数据量表。硬件配置方面,增加内存、调整缓存设置也能提升性能。 还有可能需要考虑读写分离、使用缓存机制如Redis,或者引入搜索引擎如Elasticsearch。定期维护,比如重建索引、清理数据,也是不可忽视的。如果这些还不够,可能需要分布式数据库解决方案。 需要注意用户的数据量是一百万,这个级别可能分区或分表已经有效,但分布式可能暂时不需要。还要提醒用户具体方法要根据数据库类型(比如MySQL、PostgreSQL)来调整,因为不同DBMS有不同的优化手段。 最后,应该分点说明,结构清晰,让用户能逐步排查优化。可能还要提到分析执行计划,使用慢查询日志等工具,帮助定位问题。</think>优化百万级数据查询速度需要从数据库设计、索引策略、查询优化、硬件配置等多方面入手,以下分层次介绍常见优化方案: --- ### **一、数据库设计优化** 1. **合理设计表结构** - **正规化与反正规化** 根据业务场景平衡数据冗余:高频查询的关联表可适度反规范化(如冗余关键字段),减少 JOIN 操作。 - **选择合适的数据类型** 使用最小适用类型(如 `INT` 代替 `BIGINT`,`VARCHAR(255)` 改为合理长度),避免 `TEXT/BLOB` 存储高频查询字段。 2. **分区表(Partitioning)** 按时间、地域等业务维度分区(如按月份划分),缩小单次查询扫描范围。 --- ### **二、索引优化(核心手段)** 1. **创建高效索引** - **覆盖索引(Covering Index)** 索引包含查询所需全部字段(如 `INDEX (a, b)` 对应 `SELECT a, b FROM table`),避免回表。 - **复合索引顺序** 遵循最左前缀原则,高频条件字段放左侧(如 `WHERE a=1 AND b=2` 创建 `INDEX(a, b)`)。 - **避免过度索引** 索引过多会降低写入速度,定期清理无用索引。 2. **索引类型选择** - **B-Tree**:默认结构,适合范围查询(`>`, `<`, `BETWEEN`)。 - **Hash**:仅精确匹配(`=`),不支持排序(如 MySQL MEMORY 引擎)。 - **全文索引**:针对文本搜索(如 `LIKE '%keyword%'` 优化)。 3. **索引失效场景规避** - 避免对索引字段使用函数(如 `WHERE YEAR(date) = 2023` → 改为范围查询)。 - 注意隐式类型转换(如字符串字段用数字查询)。 - 减少 `OR` 条件(可拆分为 UNION 查询)。 --- ### **三、SQL 查询优化** 1. **精简查询逻辑** - 避免 `SELECT *`,只取必要字段。 - 使用 `LIMIT` 分页,避免全表扫描(分页深度大时考虑游标分页)。 - 用 `EXISTS` 替代 `IN` 子查询(尤其关联大表时)。 2. **JOIN 优化** - 小表驱动大表(如 `LEFT JOIN` 小表在左侧)。 - 确保关联字段有索引。 3. **预计算与缓存** - 对复杂统计使用物化视图(Materialized View)或定时汇总表。 - 缓存高频查询结果(如 Redis)。 --- ### **四、分库分表与读写分离** 1. **垂直拆分** 按业务模块拆分表(如订单表与日志表分离)。 2. **水平分片(Sharding)** 单表过大时按哈希、范围等策略分片(如用户 ID 取模分 10 张表)。 3. **读写分离** 主库处理写操作,从库处理读查询(需解决数据同步延迟问题)。 --- ### **五、数据库配置调优** 1. **内存分配优化** - 调整 `innodb_buffer_pool_size`(MySQL)或 `shared_buffers`(PostgreSQL),通常设为物理内存的 70%-80%。 2. **日志与写入优化** - 非强一致性场景可关闭 `innodb_flush_log_at_trx_commit=2`(MySQL)。 - 批量写入使用 `INSERT ... VALUES (),(),()` 减少事务提交次数。 --- ### **六、硬件与架构升级** 1. **SSD 替代机械硬盘** 显著提升 I/O 性能。 2. **引入缓存层** 使用 Redis 缓存热点数据(如近期订单、用户信息)。 3. **使用列式数据库** 分析型场景可切换至 ClickHouse、Redshift 等列式存储数据库。 --- ### **七、监控与分析工具** 1. **执行计划分析** 使用 `EXPLAIN`(MySQL/PostgreSQL)或 `EXPLAIN ANALYZE` 查看查询路径,重点观察 `type`(扫描类型)、`rows`(预估行数)、`Extra`(是否使用临时表/文件排序)。 2. **慢查询日志** 开启慢查询日志定位耗时操作(如 MySQL 设置 `long_query_time=2s`)。 --- ### **示例:优化分页查询** **问题 SQL** ```sql SELECT * FROM orders ORDER BY id LIMIT 1000000, 10; -- 越往后越慢 ``` **优化方案** 使用游标分页(基于索引列): ```sql SELECT * FROM orders WHERE id > 1000000 ORDER BY id LIMIT 10; ``` --- ### **总结** - **100 万级数据**:通常通过索引 + 分区即可显著优化。 - **千万级以上**:需考虑分库分表或分布式数据库(如 TiDB、Cassandra)。 - **实时分析场景**:可结合 Elasticsearch 或 Apache Doris 加速检索。 建议根据实际场景逐步验证优化效果,优先解决执行时间最长的查询(遵循 80/20 法则)。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值