Minor performance improvements to item saving

pull/4108/head
Bond_009 4 years ago
parent 46c8a6c1e8
commit 48e1cf9fd7

@ -143,8 +143,17 @@ namespace Emby.Server.Implementations.Data
public IStatement PrepareStatement(IDatabaseConnection connection, string sql) public IStatement PrepareStatement(IDatabaseConnection connection, string sql)
=> connection.PrepareStatement(sql); => connection.PrepareStatement(sql);
public IEnumerable<IStatement> PrepareAll(IDatabaseConnection connection, IEnumerable<string> sql) public IStatement[] PrepareAll(IDatabaseConnection connection, IReadOnlyList<string> sql)
=> sql.Select(connection.PrepareStatement); {
int len = sql.Count;
IStatement[] statements = new IStatement[len];
for (int i = 0; i < len; i++)
{
statements[i] = connection.PrepareStatement(sql[i]);
}
return statements;
}
protected bool TableExists(ManagedConnection connection, string name) protected bool TableExists(ManagedConnection connection, string name)
{ {

@ -560,7 +560,7 @@ namespace Emby.Server.Implementations.Data
{ {
SaveItemCommandText, SaveItemCommandText,
"delete from AncestorIds where ItemId=@ItemId" "delete from AncestorIds where ItemId=@ItemId"
}).ToList(); });
using (var saveItemStatement = statements[0]) using (var saveItemStatement = statements[0])
using (var deleteAncestorsStatement = statements[1]) using (var deleteAncestorsStatement = statements[1])
@ -2925,7 +2925,7 @@ namespace Emby.Server.Implementations.Data
{ {
connection.RunInTransaction(db => connection.RunInTransaction(db =>
{ {
var statements = PrepareAll(db, statementTexts).ToList(); var statements = PrepareAll(db, statementTexts);
if (!isReturningZeroItems) if (!isReturningZeroItems)
{ {
@ -3329,7 +3329,7 @@ namespace Emby.Server.Implementations.Data
{ {
connection.RunInTransaction(db => connection.RunInTransaction(db =>
{ {
var statements = PrepareAll(db, statementTexts).ToList(); var statements = PrepareAll(db, statementTexts);
if (!isReturningZeroItems) if (!isReturningZeroItems)
{ {
@ -3718,26 +3718,31 @@ namespace Emby.Server.Implementations.Data
statement?.TryBind("@MaxPremiereDate", query.MaxPremiereDate.Value); statement?.TryBind("@MaxPremiereDate", query.MaxPremiereDate.Value);
} }
StringBuilder clauseBuilder = new StringBuilder();
const string Or = " OR ";
var trailerTypes = query.TrailerTypes; var trailerTypes = query.TrailerTypes;
int trailerTypesLen = trailerTypes.Length; int trailerTypesLen = trailerTypes.Length;
if (trailerTypesLen > 0) if (trailerTypesLen > 0)
{ {
const string Or = " OR "; clauseBuilder.Append('(');
StringBuilder clause = new StringBuilder("(", trailerTypesLen * 32);
for (int i = 0; i < trailerTypesLen; i++) for (int i = 0; i < trailerTypesLen; i++)
{ {
var paramName = "@TrailerTypes" + i; var paramName = "@TrailerTypes" + i;
clause.Append("TrailerTypes like ") clauseBuilder.Append("TrailerTypes like ")
.Append(paramName) .Append(paramName)
.Append(Or); .Append(Or);
statement?.TryBind(paramName, "%" + trailerTypes[i] + "%"); statement?.TryBind(paramName, "%" + trailerTypes[i] + "%");
} }
// Remove last " OR " // Remove last " OR "
clause.Length -= Or.Length; clauseBuilder.Length -= Or.Length;
clause.Append(')'); clauseBuilder.Append(')');
whereClauses.Add(clauseBuilder.ToString());
whereClauses.Add(clause.ToString()); clauseBuilder.Length = 0;
} }
if (query.IsAiring.HasValue) if (query.IsAiring.HasValue)
@ -3757,23 +3762,35 @@ namespace Emby.Server.Implementations.Data
} }
} }
if (query.PersonIds.Length > 0) int personIdsLen = query.PersonIds.Length;
if (personIdsLen > 0)
{ {
// TODO: Should this query with CleanName ? // TODO: Should this query with CleanName ?
var clauses = new List<string>(); clauseBuilder.Append('(');
var index = 0;
foreach (var personId in query.PersonIds) Span<byte> idBytes = stackalloc byte[16];
for (int i = 0; i < personIdsLen; i++)
{ {
var paramName = "@PersonId" + index; string paramName = "@PersonId" + i;
clauseBuilder.Append("(guid in (select itemid from People where Name = (select Name from TypedBaseItems where guid=")
.Append(paramName)
.Append("))) OR ");
clauses.Add("(guid in (select itemid from People where Name = (select Name from TypedBaseItems where guid=" + paramName + ")))"); if (statement != null)
statement?.TryBind(paramName, personId.ToByteArray()); {
index++; query.PersonIds[i].TryWriteBytes(idBytes);
statement.TryBind(paramName, idBytes);
}
} }
var clause = "(" + string.Join(" OR ", clauses) + ")"; // Remove last " OR "
whereClauses.Add(clause); clauseBuilder.Length -= Or.Length;
clauseBuilder.Append(')');
whereClauses.Add(clauseBuilder.ToString());
clauseBuilder.Length = 0;
} }
if (!string.IsNullOrWhiteSpace(query.Person)) if (!string.IsNullOrWhiteSpace(query.Person))
@ -5149,7 +5166,8 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
CheckDisposed(); CheckDisposed();
var itemIdBlob = itemId.ToByteArray(); Span<byte> itemIdBlob = stackalloc byte[16]
itemId.TryWriteBytes(itemIdBlob);
// First delete // First delete
deleteAncestorsStatement.Reset(); deleteAncestorsStatement.Reset();
@ -5165,17 +5183,15 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
for (var i = 0; i < ancestorIds.Count; i++) for (var i = 0; i < ancestorIds.Count; i++)
{ {
if (i > 0)
{
insertText.Append(',');
}
insertText.AppendFormat( insertText.AppendFormat(
CultureInfo.InvariantCulture, CultureInfo.InvariantCulture,
"(@ItemId, @AncestorId{0}, @AncestorIdText{0})", "(@ItemId, @AncestorId{0}, @AncestorIdText{0}),",
i.ToString(CultureInfo.InvariantCulture)); i.ToString(CultureInfo.InvariantCulture));
} }
// Remove last ,
insertText.Length--;
using (var statement = PrepareStatement(db, insertText.ToString())) using (var statement = PrepareStatement(db, insertText.ToString()))
{ {
statement.TryBind("@ItemId", itemIdBlob); statement.TryBind("@ItemId", itemIdBlob);
@ -5185,8 +5201,9 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
var index = i.ToString(CultureInfo.InvariantCulture); var index = i.ToString(CultureInfo.InvariantCulture);
var ancestorId = ancestorIds[i]; var ancestorId = ancestorIds[i];
ancestorId.TryWriteBytes(itemIdBlob);
statement.TryBind("@AncestorId" + index, ancestorId.ToByteArray()); statement.TryBind("@AncestorId" + index, itemIdBlob);
statement.TryBind("@AncestorIdText" + index, ancestorId.ToString("N", CultureInfo.InvariantCulture)); statement.TryBind("@AncestorIdText" + index, ancestorId.ToString("N", CultureInfo.InvariantCulture));
} }
@ -5466,7 +5483,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
connection.RunInTransaction( connection.RunInTransaction(
db => db =>
{ {
var statements = PrepareAll(db, statementTexts).ToList(); var statements = PrepareAll(db, statementTexts);
if (!isReturningZeroItems) if (!isReturningZeroItems)
{ {

@ -513,10 +513,11 @@ namespace Emby.Server.Implementations.Library
throw new ArgumentNullException(nameof(type)); throw new ArgumentNullException(nameof(type));
} }
if (key.StartsWith(_configurationManager.ApplicationPaths.ProgramDataPath, StringComparison.Ordinal)) string programDataPath = _configurationManager.ApplicationPaths.ProgramDataPath;
if (key.StartsWith(programDataPath, StringComparison.Ordinal))
{ {
// Try to normalize paths located underneath program-data in an attempt to make them more portable // Try to normalize paths located underneath program-data in an attempt to make them more portable
key = key.Substring(_configurationManager.ApplicationPaths.ProgramDataPath.Length) key = key.Substring(programDataPath.Length)
.TrimStart('/', '\\') .TrimStart('/', '\\')
.Replace('/', '\\'); .Replace('/', '\\');
} }
@ -871,17 +872,17 @@ namespace Emby.Server.Implementations.Library
public Guid GetStudioId(string name) public Guid GetStudioId(string name)
{ {
return GetItemByNameId<Studio>(Studio.GetPath, name); return GetItemByNameId<Studio>(Studio.GetPath(name));
} }
public Guid GetGenreId(string name) public Guid GetGenreId(string name)
{ {
return GetItemByNameId<Genre>(Genre.GetPath, name); return GetItemByNameId<Genre>(Genre.GetPath(name));
} }
public Guid GetMusicGenreId(string name) public Guid GetMusicGenreId(string name)
{ {
return GetItemByNameId<MusicGenre>(MusicGenre.GetPath, name); return GetItemByNameId<MusicGenre>(MusicGenre.GetPath(name));
} }
/// <summary> /// <summary>
@ -943,7 +944,7 @@ namespace Emby.Server.Implementations.Library
{ {
var existing = GetItemList(new InternalItemsQuery var existing = GetItemList(new InternalItemsQuery
{ {
IncludeItemTypes = new[] { typeof(T).Name }, IncludeItemTypes = new[] { nameof(MusicArtist) },
Name = name, Name = name,
DtoOptions = options DtoOptions = options
}).Cast<MusicArtist>() }).Cast<MusicArtist>()
@ -957,13 +958,11 @@ namespace Emby.Server.Implementations.Library
} }
} }
var id = GetItemByNameId<T>(getPathFn, name); var path = getPathFn(name);
var id = GetItemByNameId<T>(path);
var item = GetItemById(id) as T;
if (item == null) if (GetItemById(id) is T item)
{ {
var path = getPathFn(name);
item = new T item = new T
{ {
Name = name, Name = name,
@ -974,15 +973,16 @@ namespace Emby.Server.Implementations.Library
}; };
CreateItem(item, null); CreateItem(item, null);
return item;
} }
return item; return null;
} }
private Guid GetItemByNameId<T>(Func<string, string> getPathFn, string name) private Guid GetItemByNameId<T>(string path)
where T : BaseItem, new() where T : BaseItem, new()
{ {
var path = getPathFn(name);
var forceCaseInsensitiveId = _configurationManager.Configuration.EnableNormalizedItemByNameIds; var forceCaseInsensitiveId = _configurationManager.Configuration.EnableNormalizedItemByNameIds;
return GetNewItemIdInternal(path, typeof(T), forceCaseInsensitiveId); return GetNewItemIdInternal(path, typeof(T), forceCaseInsensitiveId);
} }
@ -1805,21 +1805,18 @@ namespace Emby.Server.Implementations.Library
/// <param name="items">The items.</param> /// <param name="items">The items.</param>
/// <param name="parent">The parent item.</param> /// <param name="parent">The parent item.</param>
/// <param name="cancellationToken">The cancellation token.</param> /// <param name="cancellationToken">The cancellation token.</param>
public void CreateItems(IEnumerable<BaseItem> items, BaseItem parent, CancellationToken cancellationToken) public void CreateItems(IReadOnlyList<BaseItem> items, BaseItem parent, CancellationToken cancellationToken)
{ {
// Don't iterate multiple times _itemRepository.SaveItems(items, cancellationToken);
var itemsList = items.ToList();
_itemRepository.SaveItems(itemsList, cancellationToken);
foreach (var item in itemsList) foreach (var item in items)
{ {
RegisterItem(item); RegisterItem(item);
} }
if (ItemAdded != null) if (ItemAdded != null)
{ {
foreach (var item in itemsList) foreach (var item in items)
{ {
// With the live tv guide this just creates too much noise // With the live tv guide this just creates too much noise
if (item.SourceType != SourceType.Library) if (item.SourceType != SourceType.Library)

@ -257,8 +257,7 @@ namespace Emby.Server.Implementations.Security
connection.RunInTransaction( connection.RunInTransaction(
db => db =>
{ {
var statements = PrepareAll(db, statementTexts) var statements = PrepareAll(db, statementTexts);
.ToList();
using (var statement = statements[0]) using (var statement = statements[0])
{ {
@ -282,7 +281,7 @@ namespace Emby.Server.Implementations.Security
ReadTransactionMode); ReadTransactionMode);
} }
result.Items = list.ToArray(); result.Items = list;
return result; return result;
} }

@ -200,7 +200,7 @@ namespace MediaBrowser.Controller.Library
/// <summary> /// <summary>
/// Creates the items. /// Creates the items.
/// </summary> /// </summary>
void CreateItems(IEnumerable<BaseItem> items, BaseItem parent, CancellationToken cancellationToken); void CreateItems(IReadOnlyList<BaseItem> items, BaseItem parent, CancellationToken cancellationToken);
/// <summary> /// <summary>
/// Updates the item. /// Updates the item.

Loading…
Cancel
Save