question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Database indexes missing on foreign keys

See original GitHub issue

Description

UPDATE: I’ve added notes about specific indexes that need to be created below

SQL server does not enforce that indexes are created on FK columns but in many (most) cases they should have indexes since quite often is the case that these columns are queried against.

One important one that is missing is:

CREATE NONCLUSTERED INDEX TEST_IX_umbracoContentVersion_nodeId ON dbo.umbracoContentVersion (nodeId)

We query against this column a lot!

So we definitely need that Index created but there’s probably lots of others…

I found an SQL script that lists all FK columns that are missing indexes from this site: https://www.mssqltips.com/sqlservertip/5004/script-to-identify-all-nonindexed-foreign-keys-in-a-sql-server-database/

For reference, here’s an article describing the benefits of indexing FK columns: https://sqlperformance.com/2012/11/t-sql-queries/benefits-indexing-foreign-keys

Here are the results of that script:

Table_Name Column_Name
cmsContentType2ContentType childContentTypeId
cmsContentTypeAllowedContentType AllowedId
cmsDictionary parent
cmsDocumentType templateNodeId
cmsLanguageText languageId
cmsLanguageText UniqueId
cmsMember2MemberGroup MemberGroup
cmsMemberType NodeId
cmsPropertyType contentTypeId
cmsPropertyType dataTypeId
cmsPropertyType propertyTypeGroupId
cmsPropertyTypeGroup contenttypeNodeId
cmsTagRelationship propertyTypeId
cmsTagRelationship tagId
cmsTask nodeId
cmsTask parentUserId
cmsTask taskTypeId
cmsTask userId
umbracoAccess loginNodeId
umbracoAccess noAccessNodeId
umbracoAccessRule accessId
umbracoContent contentTypeId
umbracoContentSchedule languageId
umbracoContentSchedule nodeId
umbracoContentVersion nodeId
umbracoContentVersion userId
umbracoContentVersionCultureVariation availableUserId
umbracoDocumentVersion templateId
umbracoDomain domainRootStructureID
umbracoLog userId
umbracoNode nodeUser
umbracoRedirectUrl contentKey
umbracoRelation childId
umbracoRelation relType
umbracoUser2NodeNotify nodeId
umbracoUser2UserGroup userGroupId
umbracoUserGroup startContentId
umbracoUserGroup startMediaId
umbracoUserLogin userId
umbracoUserStartNode startNode
umbracoUserStartNode userId

What to fix

We definitely need the umbracoContentVersion.nodeId indexed but we should review all of the above and determine if adding indexes to any of these will be beneficial. We only really want to add indexes if they are used in queries in our codebase. Adding too many indexes will slow down data insertion which we don’t want.

In most cases you can find the “DTO” object for a table such as: Umbraco.Core.Persistence.Dtos.ContentVersionDto and then you can righ click on it’s column that you want to search for to see if it’s used in queries. For example, for the ContentVersionDto.NodeId, i right click this member and say find references in VS, then i can see how many queries it’s used in

How to fix

For indexes that should exist, the DTO classes will need to be updated to declare the index and then a migration will need to be written to add all of the new indexes.


This item has been added to our backlog AB#4131

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:12 (11 by maintainers)

github_iconTop GitHub Comments

2reactions
liamlavertycommented, Oct 9, 2019

Hey, I took a look through this last night and found the following uses on those properties. Anything that I could see definitely did a JOIN, SELECT, WHERE, ORDERBY I’ve listed as needs index. There’s a few things I couldn’t find (CMSTask for example), and then I’ve listed anything that’s just used for inserting as “no” (I assume they don’t get indexed). There’s also a handful that I didn’t know enough about the codebase to work out, where the property is handed off to another method which may or may not do querying somewhere else.

Hopefully it’s a useful start though. I found all of the dtos using the class here

If these make sense, I could maybe look at updating the DTOs to include the relevant attributes. Can you give an example of a DTO that already has an index attribute, and then I can follow that style.

Table_Name Column_Name Num Uses Needs index? Notes
cmsContentType2ContentType childContentTypeId 2 maybe? ContentTypeCommonRepository.cs orders a query by this param
ContentTypeRepositoryBase.cs uses this in 2 inserts
cmsContentTypeAllowedContentType AllowedId 5 no only used in inserts
cmsDictionary parent 4 yes DictionaryRepository.cs uses this in Where SqlSyntax.GetQuotedColumnName("Parent")
cmsDocumentType templateNodeId 2 no only used in inserts
cmsLanguageText languageId 5 yes DictionaryRepository.cs uses this in ConvertFromDto, Where LanguageID > 0
cmsLanguageText UniqueId 4 yes DictionaryRepository.cs uses this on the right hand side of a join
cmsMember2MemberGroup MemberGroup 7 yes MemberGroupRepository.cs uses this as the On part of a join. MemberRepository.cs uses this in two Where statements to find all members in a role. MemberRepository.cs uses this in two Where statements to GetByMemberGroup
cmsMemberType NodeId 1 no insert only
cmsPropertyType contentTypeId 25 yes as part of joins all over the place
cmsPropertyType dataTypeId 37 yes as part of joins all over the place
cmsPropertyType propertyTypeGroupId 23 yes as part of joins, orderbys, wheres, all over the place
cmsPropertyTypeGroup contenttypeNodeId 8 yes ContentTypeCommonRepository.cs and MemberTypeRepository.cs use this for joins
cmsTagRelationship propertyTypeId 10 yes TagRepository.cs and ContentTypeRepository.cs use this for joining
cmsTagRelationship tagId 9 yes TagRepository.cs and ContentTypeRepositoryBase.cs use this for joining
cmsTask nodeId can’t find in codebase
cmsTask parentUserId can’t find in codebase
cmsTask taskTypeId can’t find in codebase
cmsTask userId can’t find in codebase
umbracoAccess loginNodeId 3 unsure insert only
umbracoAccess noAccessNodeId 3 unsure insert only
umbracoAccessRule accessId yes DocumentRepository.cs uses for joins
umbracoContent contentTypeId 34 yes as part of joins, orderbys, wheres, all over the place
umbracoContentSchedule languageId 2 unsure used in a methd “GetIsoCodeById”
umbracoContentSchedule nodeId 7 yes Used in Wheres in DocumentRepository
umbracoContentVersion nodeId 27 yes Used in lots of wheres all over the place
umbracoContentVersion userId 7 yes used in a join in DocumentRepository.cs
umbracoContentVersionCultureVariation availableUserId 1 unsure inserts only (column name also has a “rename this” comment on it)
umbracoDocumentVersion templateId 8 unsure
umbracoDomain domainRootStructureID 3 no just used for creating new objects
umbracoLog userId 5 yes used in a join for AuditRepository.GetBaseQuery
umbracoNode nodeUser 67 yes used in a join on ContentRepositoryBase.ApplySystemOrdering, selects in EntityRepository
umbracoRedirectUrl contentKey 5 yes used in a where RedirectUrlRepository.Get
umbracoRelation childId 3 unsure appears to only be inserts
umbracoRelation relType 6 maybe? used in by RelationRepository.PerformGetAll in an orderby and PerformGetByQuery in an orderby
umbracoUser2NodeNotify nodeId 6 yes used in joins and wheres in NotificationsRepository
umbracoUser2UserGroup userGroupId 8 yes used in joins in UserGroupRepository and UserRepository
umbracoUserGroup startContentId 10 yes UserGroupRepository uses it in a GroupBy statemetn
umbracoUserGroup startMediaId 11 yes UserGroupRepository uses it in a GroupBy statemetn
umbracoUserLogin userId 2 yes used in a where on UserRepository.ClearLoginSessions
umbracoUserStartNode startNode 6 yes used in selects in UserFactory, UserRepository
umbracoUserStartNode userId 6 yes used in WhereIns in UserRepository
1reaction
Shazwazzacommented, Jan 17, 2020

Hey @liamlaverty, i think it would be easiest for now to just make the migration simple, don’t worry for now about trying to be fancy and making a single migration to do all of the indexes. Might be easiest to just start with the basics, make one migration for this one index. Don’t worry about reflection, etc…

Maybe later we can combine this into a more fancy approach to multiple indexes at once. In which case we don’t need to use reflection like is being done there, you can get a tables metadata by doing this:

var tableInfo = Context.Database.PocoDataFactory.ForType(typeof(ContentNuDto));

which will give you all of the table data you need.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Script to identify all non-indexed foreign keys in a SQL ...
In this tip we look at a script that can help you identify all foreign keys that do not have a corresponding index....
Read more >
SQL Foreign key error --Missing index for FK constraint
1 Answer 1 ... You need an index on the DID column of the Employee table if you are creating a foreign key...
Read more >
Unindexed Foreign Keys Can Make Performance Worse.
In SQL 2000 I have seen 7 missing indexes bring down the system for deleting one or more row (even in a begin...
Read more >
drop index on a foreign key column leads to missing table
This fix allows the table with missing foreign key indexes to be accessed when SET foreign_key_checks=0. When the table is accessible, the user ......
Read more >
List all foreign keys without an index in SQL Server database
Missing indices are usually identified only when users report long execution or loading times. It is much better to check databases every now ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found