데이터 베이스 MySQL 튜토리얼 使用局部索引来提升 PostgreSQL 的性能

使用局部索引来提升 PostgreSQL 的性能

Jun 07, 2016 pm 04:42 PM

大家可能还不知道 PostgreSQL 支持对表数据进行局部索引吧? 它的好处是既能加快这部分索引过的数据的读取速度, 又不会增加额外开

大家可能还不知道 PostgreSQL 支持对表数据进行局部索引吧?  它的好处是既能加快这部分索引过的数据的读取速度, 又不会增加额外开销.  对于那些反复根据给定的 WHERE 子句读出来的数据, 最好的办法就是对这部分数据索引. 这对某些需要预先进行聚集计算的特定分析工作流来说, 很合适. 本帖中, 我将举一个例子说明如何通过部分索引优化数据查询.

假设有这样一个事件表, 结构如下:

每个事件关联一个用户, 有一个 ID, 一个时间戳, 和一个描述事件的 JSON. JSON 的内容包含页面的路径, 事件的类别 (如: 单击, 网页浏览, 表单提交), 以及其他跟事件相关的属性。

我们使用这个表存储各种事件日志. 假设我们手上有个事件自动跟踪器 , 能自动记录用户的每一个点击, 每一次页面浏览, 每一次表单提交, 以便我们以后做分析. 再假设我们想做个内部用的报表(internal dashboard)显示一些有价值的数据(high-value metrics), 如:每周的注册数量, 每天应收帐款. 那么, 问题就来了. 跟这个报表相关的事件, 只占该事件表数据的一小部分 -- 网站的点击量虽然很高, 但是只有很小一部分最终成交! 而这一小部分成交数据跟其他数据混杂放在一起, 也就是说, 它的信噪比很低. 

我们现在想提高报表查询的速度.  先说注册事件吧, 我们把它定义为:注册页面(/signup/)的一次表单提交. 要获得九月份第一周的注册数量, 可以理解成:

对一个包含1千万条记录, 其中只有 3000 条是注册记录, 并且没有做过索引的数据集, 执行这样的查询需要 45 秒.

对单列做全索引(Full Indexes) : 大杂烩

提高查询速度, 比较傻的办法是: 给事件相关的各种属性创建单列索引(single-column index):(data->>'type'),(data->>'path'), 和 time. 通过 bitmap,  我们可以把这三个索引扫描结果合并起来.  如果我们只是有选择地查询其中一部分数据, 而且相关索引依然存在内存中, 查询的速度会变得很快.  刚开始查询大概用 200 毫秒, 后面会降到 20 毫秒 — 比起要花 45 秒查询的顺序扫描, 确实有明显的提高.

这种索引方式有几个弊端:

  • 数据写入的开销. 这种方式在每次 INSERT/UPDATE/DELETE 操作的时候, 需要修改这三个索引的数据.  导致像本例这样频需要繁写入数据的更新数据操作代价太高.

  • 数据查询的限制. 这种方式同时也限制了我们自定义有价值(high-value)事件类型的能力. 比方说, 我们无法在 JSON 字段上做比范围查询更复杂的查询. 具体如:通过正则表达式搜索, 或者查找路径是/signup/ 开头的页面.

  • 磁盘空间的使用. 本例中的提到的表占 6660 mb 磁盘空间, 三个索引和起来有 1026 mb, 随着时间的推移, 这些数字还会不断的暴涨.

  • 局部索引(Partial Indexes)

    我们分析用的注册事件,只占了表中全部数据的 0.03%。而全索引是对全部数据进行索引, 显然不合适。要提高查询速度, 最好的办法是用局部索引。

    以我们对注册事件的定义为过滤条件,创建一个无关列(unrelated column)索引,,通过该索引,PostgreSQL 很容易找到注册事件所在的行,查询速度自然要比在相关字段的3个全索引快的多。 尤其是对时间字段进行局部索引。具体用法如下:

    CREATE INDEX event_signups ON event (time)
    WHERE (data->>'type') = 'submit' AND (data->>'path') = '/signup/'

    这个索引的查询速度,会从刚开始的 200 毫秒, 降到 2 毫秒。只要多运行查询语句,速度自然就会加快。更重要的是,局部索引解决了前面提到的全索引的几个缺点。

  • 索引只占 96 kb 磁盘空间, 是全索引的 1026 mb 的 1/10000。

  • 只有新增的行符合注册事件的过滤条件, 才更新索引。由于符合条件的事件只有 0.03%,数据写入的性能得到很大的提高: 基本上,创建和更新这样的索引没有太大的开销。

  • 这样的局部合并(partial join) 允许我们使用 PostgreSQL 提供的各种表达式作为过滤条件。索引中用到的 WHERE 子句,跟在查询语句中的用法没什么两样, 所以我们可以写出很复杂的过滤条件。 如:正则表达式, 函数返回结果,前面提到的前缀匹配。

  • 不要索引结果是布尔值的断言

    我见过有人直接索引布尔表达式:

    (data->>'type') = 'submit' AND (data->>'path') = '/signup/'

    ,然后把时间字段放在第二项. 如:

    CREATE INDEX event_signup_time ON event
    (((data->>'type') = 'submit' AND (data->>'path') = '/signup/'), time)

    这样做的后果,比上面两种方法还要严重,因为 PostgreSQL 的查询规划器(query planner)不会将这个布尔表达式当作过滤条件。也就是说,规划器不会把它当作 WHERE 语句:

    WHERE (data->>'type') = 'submit' AND (data->>'path') = '/signup/'

    所以,我们索引的字段:

    ((data->>'type') = 'submit' AND (data->>'path') = '/signup/')

    的值始终为 true。 当我们用这个索引当作条件过滤事件的时候,不管表达式的结果是 true 还是 false,都会先把事件数据读出来,加载完后,再过滤。

    这么一来, 索引的时候会从磁盘中读取许多不必要的数据, 此外也要检查每一行数据的有效性. 拿我们例子中的数据集来说, 这样的查询第一次要 25 秒, 之后会降到 8 秒.  这样的结果比索引整个时间字段还要差一些.

    局部索引能在很大程度上, 提高那些通过断言过滤出表中一部分数据的查询的速度. 对于以流量论英雄(Judging by traffic )的 #postgresql IRC 来说, 局部索引显得有些资源利用不足. 对比全索引, 局部索引有适用范围更广的断言(greater range of predicates), 配合高选择性过滤条件(highly selective filters), 写操作和磁盘空间会变得更少. 要是你经常查询某个表中的一小部分数据, 应当优先考虑局部索引.

    是不是开始爱上 PostgreSQL 了?  要了解它的各种功能和特点, 请移步到这里 @danlovesproofs.

    想不想将强大的技术变得更易于使用? 有兴趣就给我们发邮件 jobs@heapanalytics.com.

    본 웹사이트의 성명
    본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.

    핫 AI 도구

    Undresser.AI Undress

    Undresser.AI Undress

    사실적인 누드 사진을 만들기 위한 AI 기반 앱

    AI Clothes Remover

    AI Clothes Remover

    사진에서 옷을 제거하는 온라인 AI 도구입니다.

    Undress AI Tool

    Undress AI Tool

    무료로 이미지를 벗다

    Clothoff.io

    Clothoff.io

    AI 옷 제거제

    AI Hentai Generator

    AI Hentai Generator

    AI Hentai를 무료로 생성하십시오.

    인기 기사

    R.E.P.O. 에너지 결정과 그들이하는 일 (노란색 크리스탈)
    4 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌
    R.E.P.O. 최고의 그래픽 설정
    4 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌
    R.E.P.O. 아무도들을 수없는 경우 오디오를 수정하는 방법
    4 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌
    WWE 2K25 : Myrise에서 모든 것을 잠금 해제하는 방법
    1 몇 달 전 By 尊渡假赌尊渡假赌尊渡假赌

    뜨거운 도구

    메모장++7.3.1

    메모장++7.3.1

    사용하기 쉬운 무료 코드 편집기

    SublimeText3 중국어 버전

    SublimeText3 중국어 버전

    중국어 버전, 사용하기 매우 쉽습니다.

    스튜디오 13.0.1 보내기

    스튜디오 13.0.1 보내기

    강력한 PHP 통합 개발 환경

    드림위버 CS6

    드림위버 CS6

    시각적 웹 개발 도구

    SublimeText3 Mac 버전

    SublimeText3 Mac 버전

    신 수준의 코드 편집 소프트웨어(SublimeText3)

    Alter Table 문을 사용하여 MySQL에서 테이블을 어떻게 변경합니까? Alter Table 문을 사용하여 MySQL에서 테이블을 어떻게 변경합니까? Mar 19, 2025 pm 03:51 PM

    이 기사는 MySQL의 Alter Table 문을 사용하여 열 추가/드롭 테이블/열 변경 및 열 데이터 유형 변경을 포함하여 테이블을 수정하는 것에 대해 설명합니다.

    InnoDB 전체 텍스트 검색 기능을 설명하십시오. InnoDB 전체 텍스트 검색 기능을 설명하십시오. Apr 02, 2025 pm 06:09 PM

    InnoDB의 전체 텍스트 검색 기능은 매우 강력하여 데이터베이스 쿼리 효율성과 대량의 텍스트 데이터를 처리 할 수있는 능력을 크게 향상시킬 수 있습니다. 1) InnoDB는 기본 및 고급 검색 쿼리를 지원하는 역 색인화를 통해 전체 텍스트 검색을 구현합니다. 2) 매치 및 키워드를 사용하여 검색, 부울 모드 및 문구 검색을 지원합니다. 3) 최적화 방법에는 워드 세분화 기술 사용, 인덱스의 주기적 재건 및 캐시 크기 조정, 성능과 정확도를 향상시키는 것이 포함됩니다.

    MySQL 연결에 대한 SSL/TLS 암호화를 어떻게 구성합니까? MySQL 연결에 대한 SSL/TLS 암호화를 어떻게 구성합니까? Mar 18, 2025 pm 12:01 PM

    기사는 인증서 생성 및 확인을 포함하여 MySQL에 대한 SSL/TLS 암호화 구성에 대해 설명합니다. 주요 문제는 자체 서명 인증서의 보안 영향을 사용하는 것입니다. [문자 수 : 159]

    인기있는 MySQL GUI 도구는 무엇입니까 (예 : MySQL Workbench, Phpmyadmin)? 인기있는 MySQL GUI 도구는 무엇입니까 (예 : MySQL Workbench, Phpmyadmin)? Mar 21, 2025 pm 06:28 PM

    기사는 MySQL Workbench 및 Phpmyadmin과 같은 인기있는 MySQL GUI 도구에 대해 논의하여 초보자 및 고급 사용자를위한 기능과 적합성을 비교합니다. [159 자].

    MySQL에서 큰 데이터 세트를 어떻게 처리합니까? MySQL에서 큰 데이터 세트를 어떻게 처리합니까? Mar 21, 2025 pm 12:15 PM

    기사는 MySQL에서 파티셔닝, 샤딩, 인덱싱 및 쿼리 최적화를 포함하여 대규모 데이터 세트를 처리하기위한 전략에 대해 설명합니다.

    드롭 테이블 문을 사용하여 MySQL에서 테이블을 어떻게 드롭합니까? 드롭 테이블 문을 사용하여 MySQL에서 테이블을 어떻게 드롭합니까? Mar 19, 2025 pm 03:52 PM

    이 기사에서는 Drop Table 문을 사용하여 MySQL에서 테이블을 떨어 뜨리는 것에 대해 설명하여 예방 조치와 위험을 강조합니다. 백업 없이는 행동이 돌이킬 수 없으며 복구 방법 및 잠재적 생산 환경 위험을 상세하게합니다.

    InnoDB에서 클러스터 된 인덱스와 비 클러스터 된 인덱스 (2 차 지수)의 차이. InnoDB에서 클러스터 된 인덱스와 비 클러스터 된 인덱스 (2 차 지수)의 차이. Apr 02, 2025 pm 06:25 PM

    클러스터 인덱스와 비 클러스터 인덱스의 차이점은 1. 클러스터 된 인덱스는 인덱스 구조에 데이터 행을 저장하며, 이는 기본 키 및 범위별로 쿼리에 적합합니다. 2. 클러스터되지 않은 인덱스는 인덱스 키 값과 포인터를 데이터 행으로 저장하며 비 예산 키 열 쿼리에 적합합니다.

    JSON 열에서 인덱스를 어떻게 생성합니까? JSON 열에서 인덱스를 어떻게 생성합니까? Mar 21, 2025 pm 12:13 PM

    이 기사에서는 PostgreSQL, MySQL 및 MongoDB와 같은 다양한 데이터베이스에서 JSON 열에서 인덱스를 작성하여 쿼리 성능을 향상시킵니다. 특정 JSON 경로를 인덱싱하는 구문 및 이점을 설명하고 지원되는 데이터베이스 시스템을 나열합니다.

    See all articles