{"id":30639474,"url":"https://github.com/code-vedas/rails_materialized_views","last_synced_at":"2026-02-14T19:09:02.605Z","repository":{"id":310588501,"uuid":"1033403189","full_name":"Code-Vedas/rails_materialized_views","owner":"Code-Vedas","description":"MatViews is a mountable Ruby on Rails engine that makes PostgreSQL materialized views first-class citizens in your app. From declaration to concurrent refresh, automated scheduling, metrics tracking, and large-dataset validation — MatViews helps you tame big queries and keep your reports lightning-fast.","archived":false,"fork":false,"pushed_at":"2025-08-27T04:03:29.000Z","size":348,"stargazers_count":1,"open_issues_count":85,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-08-27T12:31:25.968Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://mat-views.codevedas.com/","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Code-Vedas.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":["Code-Vedas"]}},"created_at":"2025-08-06T18:59:51.000Z","updated_at":"2025-08-27T04:03:31.000Z","dependencies_parsed_at":"2025-08-27T06:10:09.240Z","dependency_job_id":null,"html_url":"https://github.com/Code-Vedas/rails_materialized_views","commit_stats":null,"previous_names":["code-vedas/rails_materialized_views"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/Code-Vedas/rails_materialized_views","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Code-Vedas%2Frails_materialized_views","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Code-Vedas%2Frails_materialized_views/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Code-Vedas%2Frails_materialized_views/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Code-Vedas%2Frails_materialized_views/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Code-Vedas","download_url":"https://codeload.github.com/Code-Vedas/rails_materialized_views/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Code-Vedas%2Frails_materialized_views/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":272922346,"owners_count":25015769,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-30T02:00:09.474Z","response_time":77,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-08-31T00:07:21.519Z","updated_at":"2026-02-14T19:09:02.600Z","avatar_url":"https://github.com/Code-Vedas.png","language":"Ruby","readme":"# rails_materialized_views (mat_views)\n\n[![Gem](https://img.shields.io/gem/v/mat_views.svg?style=flat-square)](https://rubygems.org/gems/mat_views)\n[![CI](https://github.com/Code-Vedas/rails_materialized_views/actions/workflows/ci.yml/badge.svg)](https://github.com/Code-Vedas/rails_materialized_views/actions/workflows/ci.yml)\n[![Maintainability](https://qlty.sh/gh/Code-Vedas/projects/rails_materialized_views/maintainability.svg)](https://qlty.sh/gh/Code-Vedas/projects/rails_materialized_views)\n[![Code Coverage](https://qlty.sh/gh/Code-Vedas/projects/rails_materialized_views/coverage.svg)](https://qlty.sh/gh/Code-Vedas/projects/rails_materialized_views)\n![License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square)\n![PostgreSQL](https://img.shields.io/badge/PostgreSQL-12%2B-336791?style=flat-square\u0026logo=postgresql\u0026logoColor=white)\n\n\u003e A Rails engine to define, create, refresh, and delete **PostgreSQL materialized views** with clean APIs, background jobs, observability, and CLI tasks. Built for **high availability** and **repeatable ops**.\n\n- 📦 Engine/gem: [`mat_views/`](./mat_views)\n- 🧪 Demo app: [`mat_views_demo/`](./mat_views_demo) _(not shipped with the gem)_\n\n---\n\n## ⚡ Why materialized views? Real numbers\n\nOn a \\~50k-row dataset, reading from pre-aggregated materialized views turns heavy joins into **double-digit to triple-digit speedups** compared to running the raw SQL each time.\n\n### All features are designed to be **production-ready** with following principles\n\n- **High availability**: MVs are created and refreshed in the background, ensuring minimal downtime.\n- **Repeatable operations**: Clear APIs and CLI tasks for consistent behavior.\n- **Observability**: Track runs, errors, and performance metrics.\n- **Rails-native**: Integrates seamlessly with Active Job, Rails logger, and error handling.\n- **Extensible**: Supports multiple job adapters (ActiveJob, Sidekiq, Resque) and can be customized for specific needs.\n- **Security**: Contributions to security are encouraged, with a dedicated policy for reporting vulnerabilities.\n- **Community-driven**: Contributions are welcome, with a CLA to ensure legal clarity.\n- **All features are free and open source** under the MIT license. There is no other version or paid tier.\n\n### Sample run (5 iterations)\n\nWith 50,000 rows\n\n| view                    | iterations | baseline(ms) min\\|avg\\|max | mv(ms) min\\|avg\\|max | speedup_avg |\n| ----------------------- | ---------: | -------------------------: | -------------------: | ----------: |\n| mv_user_accounts        |          5 |             16 \\| 31 \\| 74 |          1 \\| 2 \\| 5 |        15.5 |\n| mv_user_accounts_events |          5 |            70 \\| 78 \\| 108 |          1 \\| 1 \\| 2 |        78.0 |\n| mv_user_activity        |          5 |          159 \\| 161 \\| 165 |          1 \\| 1 \\| 2 |       161.0 |\n| mv_user                 |          5 |                1 \\| 1 \\| 2 |          1 \\| 2 \\| 7 |         0.5 |\n\n### Stability check (100 iterations)\n\nWith 50,000 rows\n\n| view                    | iterations | baseline(ms) min\\|avg\\|max | mv(ms) min\\|avg\\|max | speedup_avg |\n| ----------------------- | ---------: | -------------------------: | -------------------: | ----------: |\n| mv_user_accounts        |        100 |             15 \\| 17 \\| 69 |         1 \\| 1 \\| 20 |        17.0 |\n| mv_user_accounts_events |        100 |             70 \\| 70 \\| 73 |          1 \\| 1 \\| 3 |        70.0 |\n| mv_user_activity        |        100 |          158 \\| 161 \\| 242 |          1 \\| 1 \\| 2 |       161.0 |\n| mv_user                 |        100 |                1 \\| 1 \\| 1 |          1 \\| 1 \\| 2 |         0.5 |\n\n### Takeaways\n\n- Multi-table aggregates shine: **\\~70×** (accounts+events), **\\~161×** (full activity).\n- Single-table scans: little/no benefit; use normal indexes or caching.\n- Materialize **expensive joins/aggregations** you read often.\n- PostgreSQL\n  - Materialized views (MVs) make it **faster** for complex queries, especially those involving expensive joins or aggregations.\n  - MVs are **not** a silver bullet for all queries; use them when they fit the use case.\n  - If you have a slow query with poor performance, MVs might help you speed it up significantly.\n  - MVs are not a replacement for proper indexing and query optimization.\n  - Read more about [PostgreSQL materialized views](https://www.postgresql.org/docs/current/rules-materializedviews.html).\n\n---\n\n## Features\n\n- **DB definitions**: SQL, strategy, unique index columns, dependencies\n- **Create / Refresh / Delete** services \u0026 jobs (uniform responses)\n- **Refresh strategies**: `regular`, `concurrent` (needs unique index), `swap`\n- **CLI**: Rake tasks for create/refresh/delete by name, id, or all (with confirm)\n- **Observability**: run tracking tables for create/refresh/delete\n- **Rails-native**: Active Job, `Rails.logger`, clear error reporting\n\n---\n\n## Install (engine)\n\n```ruby\n# Gemfile\ngem 'mat_views'\n```\n\n```bash\nbundle install\nbin/rails g mat_views:install\nbin/rails db:migrate\n```\n\nInit:\n\n```ruby\n# config/initializers/mat_views.rb\nMatViews.configure do |c|\n  c.job_queue = :default # default queue for background jobs\n  c.job_adapter = :active_job # (default), :sidekiq, :resque\nend\n```\n\n---\n\n## Job adapter (enqueue)\n\nAll enqueues go through the adapter - it **does not guess** backends; it uses what **you** configured:\n\n```ruby\nMatViews::Jobs::Adapter.enqueue(\n  MatViews::RefreshViewJob,\n  queue: MatViews.configuration.job_queue,\n  args:  [mat_view_definition_id, :estimated]\n)\n```\n\n- Supported backends: **ActiveJob**, **Sidekiq**, **Resque** (more welcome).\n- Configure your backend as usual; the adapter delegates accordingly.\n\n---\n\n## CLI (Rake tasks)\n\n```bash\n# Create\nbundle exec rake mat_views:create_by_name\\[VIEW_NAME,force,row_count_strategy,--yes]\nbundle exec rake mat_views:create_by_id\\[ID,force,row_count_strategy,--yes]\nbundle exec rake mat_views:create_all\\[force,row_count_strategy,--yes]\n\n# Refresh\nbundle exec rake mat_views:refresh_by_name\\[VIEW_NAME,row_count_strategy,--yes]\nbundle exec rake mat_views:refresh_by_id\\[ID,row_count_strategy,--yes]\nbundle exec rake mat_views:refresh_all\\[row_count_strategy,--yes]\n\n# Delete\nbundle exec rake mat_views:delete_by_name\\[VIEW_NAME,cascade,row_count_strategy,--yes]\nbundle exec rake mat_views:delete_by_id\\[ID,cascade,row_count_strategy,--yes]\nbundle exec rake mat_views:delete_all\\[cascade,row_count_strategy,--yes]\n```\n\n---\n\n## Demo app\n\nSee [`mat_views_demo/`](./mat_views_demo) for seeds, MV definitions, and reproducible benchmarks (not shipped with the gem).\n\n---\n\n## Contributing, Security, Conduct\n\n- **Contributing:** see [CONTRIBUTING.md](./CONTRIBUTING.md)\n- **Security policy:** see [SECURITY.md](./SECURITY.md)\n- **Code of Conduct:** see [CODE_OF_CONDUCT.md](./CODE_OF_CONDUCT.md)\n\n---\n\n## Professional support\n\nNeed help with Rails Materialized Views? We offer professional support and custom development services. Contact us at [sales@codevedas.com](mailto:sales@codevedas.com) for inquiries.\n\n## License\n\nMIT © Codevedas Inc.\n","funding_links":["https://github.com/sponsors/Code-Vedas"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcode-vedas%2Frails_materialized_views","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcode-vedas%2Frails_materialized_views","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcode-vedas%2Frails_materialized_views/lists"}