Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: Improve database performance by adding indexes #1593

Merged
merged 2 commits into from
Nov 8, 2023

Conversation

mattinannt
Copy link
Member

What does this PR do?

chore: Improve database performance by adding indexes

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • Chore (refactoring code, technical debt, workflow improvements)
  • Enhancement (small improvements)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change adds a new database migration
  • This change requires a documentation update

Copy link

vercel bot commented Nov 7, 2023

The latest updates on your projects. Learn more about Vercel for Git ↗︎

2 Ignored Deployments
Name Status Preview Comments Updated (UTC)
formbricks-cloud ⬜️ Ignored (Inspect) Visit Preview Nov 7, 2023 2:57pm
formbricks-com ⬜️ Ignored (Inspect) Visit Preview Nov 7, 2023 2:57pm

Copy link
Contributor

github-actions bot commented Nov 7, 2023

Thank you for following the naming conventions for pull request titles! 🙏

Copy link
Contributor

AttributeSettingsTab.tsx

Consider destructuring the attributeClass object to improve readability and performance. This way, you won't have to repeat attributeClass every time you need to access its properties. Also, it's a good practice to handle errors in async functions to prevent potential unhandled promise rejections.
Create Issue

    const { id, name, description, type, archived } = attributeClass;
    const defaultValues = { name, description };
    const data = { archived: !archived };

    const onSubmit = async (data) => {
      try {
        setisAttributeBeingSubmitted(true);
        setOpen(false);
        await updateAttributeClass(id, data);
        router.refresh();
      } catch (error) {
        console.error(error);
      } finally {
        setisAttributeBeingSubmitted(false);
      }
    };

    const handleArchiveToggle = async () => {
      try {
        setisAttributeBeingSubmitted(true);
        await updateAttributeClass(id, data);
      } catch (error) {
        console.error(error);
      } finally {
        setisAttributeBeingSubmitted(false);
      }
    };

packages/lib/team/service.ts

The code in the getMonthlyActiveTeamPeopleCount and getMonthlyTeamResponseCount functions can be refactored to improve performance and readability. Instead of looping through each product and environment to get the count of active people and responses, you can use Prisma's aggregate feature to count the active people and responses across all environments in one query. This reduces the number of database queries and improves performance.
Create Issue

    // Define the start of the month
    const now = new Date();
    const firstDayOfMonth = new Date(now.getFullYear(), now.getMonth(), 1);

    // Get all environment IDs for the team
    const products = await getProducts(teamId);
    const environmentIds = products.flatMap((product) => product.environments.map((env) => env.id));

    // Use Prisma's aggregate to count active people for all environments
    const peopleAggregations = await prisma.person.aggregate({
      _count: {
        id: true,
      },
      where: {
        AND: [
          { environmentId: { in: environmentIds } },
          {
            sessions: {
              some: {
                createdAt: { gte: firstDayOfMonth },
              },
            },
          },
        ],
      },
    });

    return peopleAggregations._count.id;

The code in the getMonthlyTeamResponseCount function can be refactored to improve performance and readability. Instead of looping through each product and environment to get the count of responses, you can use Prisma's aggregate feature to count the responses across all environments in one query. This reduces the number of database queries and improves performance.
Create Issue

    // Define the start of the month
    const now = new Date();
    const firstDayOfMonth = new Date(now.getFullYear(), now.getMonth(), 1);

    // Get all environment IDs for the team
    const products = await getProducts(teamId);
    const environmentIds = products.flatMap((product) => product.environments.map((env) => env.id));

    // Use Prisma's aggregate to count responses for all environments
    const responseAggregations = await prisma.response.aggregate({
      _count: {
        id: true,
      },
      where: {
        AND: [
          { survey: { environmentId: { in: environmentIds } } },
          { survey: { type: "web" } },
          { createdAt: { gte: firstDayOfMonth } },
        ],
      },
    });

    // The result is an aggregation of the total count
    return responseAggregations._count.id;

packages/lib/survey/service.ts

The functions updateSurvey, createSurvey, deleteSurvey, and duplicateSurvey in the survey/service.ts file are currently written as async functions. However, they can be refactored to arrow functions to improve readability and consistency with other functions in the file.
Create Issue

    export const updateSurvey = async (updatedSurvey: TSurvey): Promise<TSurvey> => {
      // function body
    };

    export const createSurvey = async (environmentId: string, surveyBody: TSurveyInput): Promise<TSurvey> => {
      // function body
    };

    export const deleteSurvey = async (surveyId: string) => {
      // function body
    };

    export const duplicateSurvey = async (environmentId: string, surveyId: string) => {
      // function body
    };

schema.prisma

Adding indexes to the database can significantly improve the performance of read operations. However, it's important to note that while indexes speed up read operations, they slow down write operations (such as INSERT and UPDATE) because the database needs to update the index every time a record is added or modified. Therefore, it's crucial to find a balance and only add indexes to columns that are frequently used in WHERE clauses or JOIN operations.
Create Issue

    model User {
      id                    String           @id @default(cuid())
      createdAt             DateTime         @default(now()) @map(name: "created_at")
      updatedAt             DateTime         @updatedAt @map(name: "updated_at")
      email                 String           @unique
      hashedPassword        String?
      name                  String?
      avatarUrl             String?
      emailVerified         Boolean          @default(false)
      emailVerificationCode String?          @unique
      providerAccounts      ProviderAccount[]
      memberships           Membership[]
      invitesCreated        Invite[]         @relation("inviteCreatedBy")
      invitesAccepted       Invite[]         @relation("inviteAcceptedBy")
      role                  Role?
      objective             Objective?
      notificationSettings  Json             @default("{}")
      @@index([email])
    }

Adding indexes to the database can significantly improve the performance of read operations. However, it's important to note that while indexes speed up read operations, they slow down write operations (such as INSERT and UPDATE) because the database needs to update the index every time a record is added or modified. Therefore, it's crucial to find a balance and only add indexes to columns that are frequently used in WHERE clauses or JOIN operations.
Create Issue

    model ProviderAccount {
      id                  String          @id @default(cuid())
      createdAt           DateTime        @default(now()) @map(name: "created_at")
      updatedAt           DateTime        @updatedAt @map(name: "updated_at")
      provider            IdentityProvider
      providerAccountId   String
      user                User            @relation(fields: [userId], references: [id], onDelete: Cascade)
      userId              String
      access_token        String?         @db.Text
      token_type          String?
      refresh_token       String?         @db.Text
      expires_in          Int?
      id_token            String?         @db.Text
      session_state       String?
      @@unique([provider, providerAccountId])
      @@index([userId])
    }

@mattinannt mattinannt added this pull request to the merge queue Nov 8, 2023
Merged via the queue into main with commit ca21c9c Nov 8, 2023
10 checks passed
@mattinannt mattinannt deleted the feature/add-indexes branch November 8, 2023 06:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

1 participant