私はWebアプリケーション(プロジェクト管理システム)を構築していますが、パフォーマンスに関してはこれについて疑問に思っていました。
課題テーブルがあり、その中には他のさまざまなテーブルにリンクする12の外部キーがあります。そのうち8つは、他のテーブルからタイトルフィールドを取得するために参加する必要があります。これは、Webアプリケーションでレコードが意味をなすようにするためです。これらの結合ごとに1つのフィールド。
今、永続的な理由で自動増分主キーを使用するように言われました(シャーディングがGUIDを使用する必要がある場合を除きます)が、varchar(最大長32)のパフォーマンスを使用するのはどれほど悪いですか?つまり、これらのテーブルのほとんどは、おそらく多くのレコードに含まれないでしょう(それらのほとんどは20未満でなければなりません)。また、タイトルを主キーとして使用すると、95%の時間を結合する必要がないため、SQLの95%でパフォーマンスヒットさえ発生します(私は思う)。私が考えることができる唯一の欠点は、私はより高いディスクスペース使用量を持っているということです(しかし、1日は本当に大したことです)。
列挙の代わりにこのようなものの多くにルックアップテーブルを使用している理由は、これらの値のすべてがアプリケーション自体を介してエンドユーザーによって構成可能である必要があるためです。
多くのレコードを持つことを除いて、テーブルの主キーとしてvarcharを使用することの欠点は何ですか?
更新-いくつかのテスト
それで、私はこのものでいくつかの基本的なテストをすることにしました。私は100000レコードを所有しており、これらは基本クエリです。
ベースVARCHAR FKクエリ
SELECT i.id, i.key, i.title, i.reporterUserUsername, i.assignedUserUsername, i.projectTitle,
i.ProjectComponentTitle, i.affectedProjectVersionTitle, i.originalFixedProjectVersionTitle,
i.fixedProjectVersionTitle, i.durationEstimate, i.storyPoints, i.dueDate,
i.issueSecurityLevelId, i.creatorUserUsername, i.createdTimestamp,
i.updatedTimestamp, i.issueTypeId, i.issueStatusId
FROM ProjectManagement.Issues i
ベースINT FKクエリ
SELECT i.id, i.key, i.title, ru.username as reporterUserUsername,
au.username as assignedUserUsername, p.title as projectTitle,
pc.title as ProjectComponentTitle, pva.title as affectedProjectVersionTitle,
pvo.title as originalFixedProjectVersionTitle, pvf.title as fixedProjectVersionTitle,
i.durationEstimate, i.storyPoints, i.dueDate, isl.title as issueSecurityLevelId,
cu.username as creatorUserUsername, i.createdTimestamp, i.updatedTimestamp,
it.title as issueTypeId, is.title as issueStatusId
FROM ProjectManagement2.Issues i
INNER JOIN ProjectManagement2.IssueTypes `it` ON it.id = i.issueTypeId
INNER JOIN ProjectManagement2.IssueStatuses `is` ON is.id = i.issueStatusId
INNER JOIN ProjectManagement2.Users `ru` ON ru.id = i.reporterUserId
INNER JOIN ProjectManagement2.Users `au` ON au.id = i.assignedUserId
INNER JOIN ProjectManagement2.Users `cu` ON cu.id = i.creatorUserId
INNER JOIN ProjectManagement2.Projects `p` ON p.id = i.projectId
INNER JOIN ProjectManagement2.`ProjectComponents` `pc` ON pc.id = i.projectComponentId
INNER JOIN ProjectManagement2.ProjectVersions `pva` ON pva.id = i.affectedProjectVersionId
INNER JOIN ProjectManagement2.ProjectVersions `pvo` ON pvo.id = i.originalFixedProjectVersionId
INNER JOIN ProjectManagement2.ProjectVersions `pvf` ON pvf.id = i.fixedProjectVersionId
INNER JOIN ProjectManagement2.IssueSecurityLevels isl ON isl.id = i.issueSecurityLevelId
また、次の追加でこれらのクエリを実行しました。
- 特定の項目を選択します(i.key = 43298)
- i.idによるグループ化
- 順序(int FKの場合はit.title、varchar FKの場合はi.issueTypeId)
- 制限(50000、100)
- グループ化して一緒に制限する
- グループ化、順序付け、および制限
これらの結果は次のとおりです。
クエリタイプ:VARCHAR FK TIME / INT FK TIME
基本クエリ:〜4ms /〜52ms
特定の項目を選択してください:〜140ms /〜250ms
i.idによるグループ化:〜4ms /〜2.8sec
オーダー:〜231ms /〜2sec
制限:〜67ms /〜343ms
グループ化と制限:〜504ms /〜2sec
グループ化、順序付け、および制限:〜504ms /~2.3sec
現在、どちらか一方(または両方)を高速化するためにどのような構成を行うことができるかわかりませんが、データのクエリでVARCHAR FKがより高速に表示されるようです(場合によってははるかに高速です)。
その速度の改善が追加のデータ/インデックスサイズの価値があるかどうかを選択する必要があると思います。