С# выполняет скаляр очень медленно на большой таблице

У меня проблема с очень медленным выполнением executescalar в таблице с более чем 200 000 записей.

Метод, который я использую, проверяет, существует ли varchar в таблице, и возвращает счетчик, чтобы увидеть, можно ли что-нибудь найти:

public static bool AlreadyQueued(string url)
{
    using (SqlConnection connection = new SqlConnection(_connectionString))
    {
        SqlCommand cmd = new SqlCommand("SELECT Count(queueID) from PriorityQueue where absolute_url = @url")
        {
            Connection = connection,
            CommandType = CommandType.Text
        };
        cmd.Parameters.AddWithValue("@url", url);
        connection.Open();
        var count = (int)cmd.ExecuteScalar();
        return count > 0;
    }
}

Моя таблица построена так:

CREATE TABLE PriorityQueue
(
    queueID int IDENTITY(1,1) PRIMARY KEY,
    absolute_url varchar (900),
    depth int,
    priorty int
);

Есть ли способ ускорить мой метод С# или мне нужно что-то изменить в моей таблице?


person R.hagens    schedule 22.11.2016    source источник
comment
Попробуйте добавить индекс в столбец URL в таблице.   -  person Praveen    schedule 22.11.2016
comment
Дело не в том, что ваш метод медленный. Это ваш запрос занимает много времени. Вы можете добавить индекс к absolute_url, чтобы сделать его немного быстрее, но для большой таблицы это займет время, как и предполагалось.   -  person Mahesh    schedule 22.11.2016
comment
Кроме того, если вы часто используете этот запрос с разными URL-адресами, лучше не использовать метод Add для определения вашего параметра. Метод Add позволяет указать тип и размер параметра. В частности, использование свойства Size (=100) очень помогает оптимизатору ядра базы данных повторно использовать план запроса и ускорить работу базы данных.   -  person Steve    schedule 22.11.2016
comment
Я не думаю, что вы можете решить эту проблему в базе данных. Попробуйте добавить какой-нибудь слой кэша в свое приложение, чтобы повысить производительность. Избегайте ненужных запросов к БД.   -  person Daniel    schedule 22.11.2016
comment
Я благодарю всех за хорошие ответы, это действительно решило мою проблему.   -  person R.hagens    schedule 22.11.2016


Ответы (5)


Медлительность в базе данных, как уже указывалось другими. Поскольку вам действительно не нужен точный счет, а скорее логическое значение, указывающее, существует ли строка или нет, вы можете получить небольшое увеличение производительности, например:

SELECT TOP 1 1 from PriorityQueue where absolute_url = @url

С помощью этого запроса база данных может прекратить поиск, как только будет найдено первое (и, возможно, единственное) совпадение.

Но чтобы получить значительный прирост производительности, вам нужно добавить индекс к столбцу absolute_url. Но этот столбец в настоящее время определяется как varchar(900), что (если я правильно погуглил) находится прямо на пределе того, как долго столбец может находиться в индексе. Если вы проиндексируете его как таковой, индекс займет примерно столько же места, сколько и сама таблица.

Поэтому, если возможно, сократите столбец, а затем добавьте к нему индекс. Если вы абсолютно не можете сократить его, вы можете добавить еще один столбец, который содержит первые (скажем) 50 символов столбцов, а затем вместо этого проиндексировать этот столбец. Тогда вы можете сделать так:

SELECT TOP 1 1 from PriorityQueue where absolute_url = @url and shortened_url = @shortenedUrl

Затем вам также нужно добавить параметр @shortenedUrl, который должен (конечно) содержать первые 50 символов URL-адреса, который вы ищете.

person user1429080    schedule 22.11.2016

ExecuteScalar() используется только для выполнения вашего запроса, выборка данных занимает больше времени.

person rani    schedule 22.11.2016

Счетчик SQL всегда медленный с большим количеством записей. Пожалуйста, ищите альтернативные варианты. Вы можете использовать, если существует или любой другой вариант в соответствии с вашими требованиями.

Ниже приведены некоторые ссылки, которые помогут вам понять это.

Счетчик SQL Server работает медленно

производительность SQL count(*)

SQL Server — ускорение подсчета в большой таблице

person Banketeshvar Narayan    schedule 22.11.2016

Выбор 20 000 строк всегда будет немного медленным, поэтому может быть хорошей идеей просмотреть ваши индексы и, возможно, выполнить AlreadyQueued в фоновом режиме.

https://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker(v=vs.110).aspx

person Alec.    schedule 22.11.2016

Вы пробовали "SELECT TOP 1 queueID from PriorityQueue where absolute_url = @url" вместо этого? Должен быть заметный прирост производительности.

В любом случае, я предлагаю вам добавить хранимую процедуру в вашу базу данных, чтобы вернуть желаемое логическое значение.

Create PROCEDURE UrlFound @absolute_url varchar(900)  
AS  
IF (EXISTS(SELECT TOP 1 1 from PriorityQueue where absolute_url = @absolute_url))
    RETURN 1  
ELSE  
   RETURN 0;  
GO  

Затем вы можете протестировать его следующим образом:

DECLARE @result bit
exec @result = UrlFound 'YourAbsoluteUrl'
print @result 
person Innat3    schedule 22.11.2016