2009-11-24 5 views
1

OK. Я использую язык программирования C# для доступа к простой базе данных (на Microsoft SQL Server)Можно ли выполнить двоичный поиск в базе данных в SQL?

В настоящее время я использую объект DataReader для доступа к базе данных. Итак, вот мой вопрос: возможно ли выполнить бинарный поиск (в C#) для определенной части данных, чтобы я мог быстрее выполнять поиск?

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

while (pReader.Read()) 
{ 
    if ((String)pReader["theData"] == "The_thing_im_searching_for") 
    break; 
} 

Так есть ли способ сделать двоичный поиск?

ответ

16

Если вы используете базу данных в любом случае, вы должны написать инструкцию select, чтобы искать то, что ищете, а не итерировать через базу данных вручную. Нет причин изобретать велосипед.

5

Как указывает Донни, если вы выражаете свой предикат в SQL, база данных будет выбирать наиболее эффективный способ извлечения ваших данных автоматически.

Попробуйте это:

string sql = "SELECT * FROM Foo WHERE theData = 'The_thing_im_searching_for'" 
SqlDataAdapter adapter = new SqlDataAdapter(sql); 
DataTable table = new DataTable(); 
adapter.Fill(table); 

foreach(DataRow row in table.Rows) { 
    // Do whatever you want here 
} 
0

Daniel и Донни ответы здесь говорю вам, что это плохая идея очень правильная.

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

MSSQL может хранить данные в формате varbinary, и вы можете выполнять поиск по этим двоичным данным. На самом деле вы можете найти дополнительную информацию об этом в этом сообщении: Dealing with a varbinary field in VB.NET

Вот пример запроса, выполняющего именно это.

byteArrayToken = StringToByteArray(stringToken) 
scSelectThing.CommandText = "select thing from table where [email protected]" 
Dim param As SqlParameter = scSelectThing.Parameters.Add("@token", SqlDbType.VarBinary) 
param.Value = byteArrayToken 
lbOutput2.Text = scSelectThing.ExecuteScalar() 
+0

Особая благодарность Адаму Робинсону за помощь в этом вопросе. –

+2

Подходит для тщательного ответа, но в контексте вопроса я думаю, что он имел в виду «алгоритм бинарного поиска», а не «алгоритм поиска двоичных данных». –

2

В духе Donnies ответа, я предоставил простой SQL пример того, как получить то, что вы после использования более защищаемого механизма чем динамически построенного SQL (как и другие посоветовали вам)

В простом случае вы должны создать хранимую процедуру для каждой операции создания, чтения, обновления, удаления, доступной для приложения, для каждого объекта в базе данных. (Это не 100% истинно в больших производственных системах, но это лучше, чем динамически созданный SQL, построенный в приложении)

Теперь для READ в этом списке перечислены все, если параметр не указан. Это упрощенная версия подхода, на котором архитектор базы данных на моей работе читал лекции - здесь мы не отделяем извлеченную хранимую процедуру от процедуры листинга, они фактически выполняют ту же операцию. Это будет выплачиваться в меньшем количестве SQL-кода для поддержки в долгосрочной перспективе.

CREATE PROCEDURE usp_ReadName 
@name_id bigint=NULL 
AS 
BEGIN 
SET NOCOUNT ON; 
if (@name_id IS NULL) 
    SELECT name_id,name,description 
      from name with(nolock) 
else 
    select name_id,name,description 
      from name with(nolock) 
      where name_id = @name_id 
END 
GO 

Теперь для C# стороны. Для хранения результатов мы определяем объект передачи данных. Вообще говоря, это более легкий вес, чем данные, более быстрые и эффективные в использовании. Если скорость, большие объемы данных или ограниченная память не являются предметом озабоченности, просто используйте данные с данными.(В среднем вы будете экономить примерно 40% + память, и около 10% скорости - 100K записи структуры выше использования пиков памяти на 140MB с DataTable, а пики DTE на 78MB)

/// <summary> 
/// A simple data transfer entity 
/// </summary> 
public struct name_data 
{ 
    public long name_id; 
    public string name; 
    public string description; 
    public name_data(long id, string n, string d) 
    { 
     name_id = id; 
     name = n; 
     description = d; 
    } 
} 

Теперь мы фиксируем результаты в C# с использованием синтаксиса с нулевым параметром. Этот код предполагает, что вы уже открыли соединение SQL

conn.Open(); 
using (SqlCommand cmd = new SqlCommand("usp_ReadName",conn)) 
{ 
    cmd.CommandType = CommandType.StoredProcedure; 
    if (id.HasValue) 
     cmd.Parameters.Add("@name_id", SqlDbType.BigInt).Value = id.Value; 
    using (SqlDataReader reader = cmd.ExecuteReader()) 
    { 

     if (reader.HasRows) 
     { 
      while (reader.Read()) 
      { 
       dte.name_data item = new dte.name_data(
        (long)reader["name_id"], 
        reader["name"].ToString(), 
        reader["description"].ToString()); 
       items.Add(item); 
      } 
     } 
    } 
} 
+0

Не то, чтобы информация была плохая, но это серьезный перебор, учитывая его утверждение простой базы данных. Кроме того, среди разработчиков БД все еще есть довольно здоровые дискуссии о преимуществах делать все в sprocs vs на стороне клиента SQL, поэтому я бы не стал передавать это, так как Евангелие-правда-одно-истинное все же. :) – Donnie

+0

Хорошо также отметить, что я не сказал «делать все в хранимых процедурах». Я сказал: «В простом случае вы должны создать хранимую процедуру для каждой операции« Создать, прочитать, обновить, удалить », доступную для приложения, для каждого объекта в базе данных». Это было связано с созданием более безопасного (т. Е. От SQL-инъекции, * да, это технически возможно, если вы действительно любите вещи в хранимой процедуре *, но это обычно не область простых операций CRUD) Я даже сказал что на больших производственных системах выполнение операций CRUD таким образом не всегда было правильным. –

0

Так есть ли способ сделать бинарный поиск ?

Проблема с прямым SELECT на стороне SQL Server заключается в том, что БД будет выполнять линейный поиск по таблице, если столбец, с которым вы работаете, имеет индекс на нем; то БД может быть более умным.

Если вам все равно нужно прочитать всю таблицу (например, чтобы вы могли выполнить поиск заново через некоторое время), вы можете подумать об использовании ArrayList.BinarySearch(). Разумеется, для того, чтобы работать, данные должны быть отсортированы в ArrayList.

+0

Если вы ищете в столбце, решение обычно помещает на него индекс, чтобы предотвратить полное сканирование таблицы (то есть линейный поиск). И, как вы указали, есть ли у вас все в памяти, его нужно будет отсортировать соответствующим образом. (Или вы можете свободно использовать словарь класс ...) Однако, если кто-то не использует индексы в базе данных и один раз считывает все данные и ищет их в памяти, мне интересно, почему они вообще беспокоятся о базе данных. (например, что, если новые записи, представляющие интерес, добавляются другим пользователем, как это может узнать об этом примере приложения?) –

+0

Если новые записи добавлены другим пользователем (или другим веб-сервером), вы можете использовать классы SqlDependency или SqlCacheDependency чтобы SQL Server отправил вам уведомление об изменении. – RickNZ

0

Спасибо за всю информацию (Jay Here again). Я верю, что ответили на мой вопрос.

Дело в том, что у меня много информации в базе данных. Поиск определенного элемента займет много времени. Поэтому мне было интересно выполнить двоичный поиск.

Когда я выполняю команду SELECT, чтобы найти что-то, я не знаю, выполняет ли MSSQL (на заднем плане) двоичный поиск. Но если то, что RickNZ (выше) говорит, правда

Проблемы с прямым ВЫБРАТЬ на стороне SQL Server является то, что DB будет делать линейный поиск через таблицы, если в колонке вы работаете с индексом на нем; то БД может быть более умным.

Тогда база данных будет выполнять поиск наиболее эффективно (двоичный поиск), если бы у меня была информация «проиндексирована».