[OLEDB ] Количество записей в запросе и жуткие тормоза
От: andy_84 Россия  
Дата: 16.10.08 08:47
Оценка:
Доброе время суток. Проблема следующая.

Есть MSSQL сервер, с которым работаю через OLEDB. Есть на сервере таблица с миллионом записей.
Запрос к таблице делаю следующим образом:
CCommand<CAccessor<CMyAccessor> > command;
HRESULT hr = command.Open(Session, Select);

При этом вызов Open() для Select = "SELECT * FROM Table_name" занимает меньше секунды, а проход по записям при помощи MoveNext() — секунд 40. Это устраивает.

Теперь встала задача получить количество записей в запросе. У Open'а среди параметров есть DBROWCOUNT* pRowsAffected,
куда это количество записывается. Однако простой вызов
HRESULT hr = command.Open(Session, Select, 0, &RowsAffected);

Пишет в RowsAffected -1, означающий, что "The number of affected rows is not available" (с) MSDN. Хорошо, пробуем сделать например так
CDBPropSet ps(DBPROPSET_ROWSET);
ps.AddProperty(DBPROP_CANHOLDROWS, true);

HRESULT hr = command.Open(Session, Select, &ps, &RowsAffected);

При этом в RowsAffected успешно записывается кол-во записей, но этот вызов Open() выполняется 12 сек, а сам проход по записям работает раз в 15 медленнее предыдущего варианта. Что неприемлимо.

Просмотрел много сообщений и на здешнем форуме, и в гугле искал — все спрашивают, как получить кол-во записей, но никто не волновался о скорости последующего прохода.

Знает кто-нибудь, как получить кол-во записей в запросе и не потерять в скорости ?
Заранее благодарю.
Re: [OLEDB ] Количество записей в запросе и жуткие тормоза
От: Nonmanual Worker  
Дата: 16.10.08 09:22
Оценка:
Здравствуйте, andy_84, Вы писали:

_>Знает кто-нибудь, как получить кол-во записей в запросе и не потерять в скорости ?

_>Заранее благодарю.

А выполнить запрос SELECT count(*) FROM Table_name идеология не позволяет?
Re[2]: [OLEDB ] Количество записей в запросе и жуткие тормоз
От: andy_84 Россия  
Дата: 16.10.08 09:47
Оценка:
Здравствуйте, Nonmanual Worker, Вы писали:

NW>А выполнить запрос SELECT count(*) FROM Table_name идеология не позволяет?


Собственно, этот запрос был представлен в качестве примера, чтобы просто оценить скорость работы.
Реально запросы будут разные и намного сложнее, поэтому парсить их самому и приделывать к ним COUNT я не собираюсь.
Re[3]: [OLEDB ] Количество записей в запросе и жуткие тормоз
От: Nonmanual Worker  
Дата: 16.10.08 10:40
Оценка:
Здравствуйте, andy_84, Вы писали:

_>Собственно, этот запрос был представлен в качестве примера, чтобы просто оценить скорость работы.

_>Реально запросы будут разные и намного сложнее, поэтому парсить их самому и приделывать к ним COUNT я не собираюсь.

Но видимо прийдется. Я немного представляю, как работают сервера баз данных (правда не конкретно про SQL Server), и скорее всего тормоза не получится победить (затык будет или на обработке сервером запроса, или при выборке данных клиентом). Да, кстати, еще посмотрите потребление памяти клиентом при установленном DBPROP_CANHOLDROWS и без него.

Но главный запрос такой: Зачем вам нужно знать сколько записей возвращается? Не для того ли, что прогресс нарисовать?
Re: [OLEDB ] Количество записей в запросе и жуткие тормоза
От: Nonmanual Worker  
Дата: 16.10.08 10:52
Оценка:
Здравствуйте, andy_84, Вы писали:

_>Знает кто-нибудь, как получить кол-во записей в запросе и не потерять в скорости ?

_>Заранее благодарю.

Еще можно попробывать @@ROWCOUNT, но там тонкости есть.
Re[4]: [OLEDB ] Количество записей в запросе и жуткие тормоз
От: Соловьев Андрей Россия  
Дата: 16.10.08 10:55
Оценка:
Здравствуйте, Nonmanual Worker, Вы писали:

NW>Да, кстати, еще посмотрите потребление памяти клиентом при установленном DBPROP_CANHOLDROWS и без него. Но главный запрос такой: Зачем вам нужно знать сколько записей возвращается? Не для того ли, что прогресс нарисовать?


На потреблении памяти не сказывается.
Да, действительно, мне нужно сделать прогресс
Re: [OLEDB ] Количество записей в запросе и жуткие тормоза
От: MasterZiv СССР  
Дата: 16.10.08 14:42
Оценка:
andy_84 wrote:

> Теперь встала задача получить количество записей в запросе. У Open'а

> среди параметров есть DBROWCOUNT* pRowsAffected,
> куда это количество записывается. Однако простой вызов
>
> HRESULT hr = command.Open(Session, Select, 0, &RowsAffected);
>
>
> Пишет в RowsAffected -1, означающий, что "The number of affected rows is
> not available" (с) MSDN. Хорошо, пробуем сделать например так

Это -- старая фича. В реляционных СУБД невозможно вообще
получить кол-во строк, которые возвращает запрос.
Чтобы его получить, вы должны прочитать все строки.
И посчитать их. Именно это и делает внутри OLEDB (или другие API).

Так что просто меняйте подход -- выполняйте запрос, получайте
данные, потом считайте строки и обрабатывайте их.
Posted via RSDN NNTP Server 2.1 beta
Re[3]: [OLEDB ] Количество записей в запросе и жуткие тормоз
От: Disappear  
Дата: 16.10.08 15:28
Оценка: 3 (2)
_>Собственно, этот запрос был представлен в качестве примера, чтобы просто оценить скорость работы.
_>Реально запросы будут разные и намного сложнее, поэтому парсить их самому и приделывать к ним COUNT я не собираюсь.

Парсить не нужно, а приделывать очень просто.
SELECT COUNT(*) FROM (<any query>) A
Оптимизатор любой адекватной СУБД это проглотит.
Re[2]: [OLEDB ] Количество записей в запросе и жуткие тормоз
От: Disappear  
Дата: 16.10.08 15:32
Оценка:
MZ>Это -- старая фича. В реляционных СУБД невозможно вообще
MZ>получить кол-во строк, которые возвращает запрос.

Это не совсем так, во многие СУБД могут определить количество строк не выполняя выборки как таковой. Это делается еще на этапе оптимизации запроса. Количество может быть определена по индексу (если есть условие), статистике (если выборка по полной таблице) и прочие варианты.. иногда количество может быть определено не точно с последующим уточнением. Все зависит от крутизны СУБД. Во многих случаях запросы типа SELECT COUNT(*) FROM (<some query>) as A могут быть выполнены без реального выполнения <some query>
Re[3]: [OLEDB ] Количество записей в запросе и жуткие тормоз
От: MasterZiv СССР  
Дата: 16.10.08 18:51
Оценка: +1
Disappear wrote:

> Это не совсем так, во многие СУБД могут определить количество строк не

> выполняя выборки как таковой.

Нет, невозможно, вы ошибаетесь.

Это делается еще на этапе оптимизации
> запроса. Количество может быть определена по индексу (если есть
> условие), статистике (если выборка по полной таблице) и прочие
> варианты..

Это — неточное кол-во записей.
Оно даже на самом деле не абсолютное количество записей,
а относительное для разных вариантов планов запросов.

иногда количество может быть определено не точно с
> последующим уточнением.

Для уточнения надо было бы выполнить полностью запрос.


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

Все зависит от крутизны СУБД. Во многих случаях
> запросы типа SELECT COUNT(*) FROM (<some query>) as A могут быть
> выполнены без реального выполнения <some query>

ага, ну да, у "крутых" СУБД есть такая волшебная палочка,
вот она раз! как взмахнёт ею, и — пожалуйста, уже знает
кол-во записей !
Posted via RSDN NNTP Server 2.1 beta
Re[2]: [OLEDB ] Количество записей в запросе и жуткие тормоз
От: andy_84 Россия  
Дата: 17.10.08 05:07
Оценка:
Здравствуйте, Nonmanual Worker, Вы писали:

NW>Еще можно попробывать @@ROWCOUNT, но там тонкости есть.


Попробовал сейчас сделать так:
CCommand<CAccessor<CMyAccessor> > command;
HRESULT hr = command.Open(Session, Select);

CCommand<CAccessor<CRowCountAccessor> > row_count;
row_count.m_RowCount = 777;
hr = row_count.Open(m_Session, L"SELECT @@ROWCOUNT as row_count");

Так вот после второго вызова hr == S_OK, а m_RowCount равно 0, при том что первый запрос вернул отличное от 0 число записей. Может я не учел эти самые тонкости?

Попробую сейчас сделать через IMultipleResults, мож че получится
Re[4]: [OLEDB ] Количество записей в запросе и жуткие тормоз
От: Nonmanual Worker  
Дата: 17.10.08 05:38
Оценка:
Здравствуйте, Disappear, Вы писали:

D>Парсить не нужно, а приделывать очень просто.

D>SELECT COUNT(*) FROM (<any query>) A
D>Оптимизатор любой адекватной СУБД это проглотит.

Кстати, это хороший вариант.
Присоединюсь, и посоветую andy_84 сделать данным образом.
Re[3]: [OLEDB ] Количество записей в запросе и жуткие тормоз
От: Nonmanual Worker  
Дата: 17.10.08 05:46
Оценка:
Здравствуйте, andy_84, Вы писали:

_>Попробую сейчас сделать через IMultipleResults, мож че получится


Должно получится.
Re[4]: [OLEDB ] Количество записей в запросе и жуткие тормоз
От: Disappear  
Дата: 17.10.08 08:23
Оценка:
Здравствуйте, MasterZiv, Вы писали:

MZ>Disappear wrote:


>> Это не совсем так, во многие СУБД могут определить количество строк не

>> выполняя выборки как таковой.

MZ>Нет, невозможно, вы ошибаетесь.


По индексу количесто записей известно точно.
Знаю точно, что вот эта СУБД (www.qdtechnology.com) это умеет. Знаю, собственно потому, что сам писал ее оптимизатор.
Уточнение может быть произведено не полной выборкой данных, так как статистика позволяет отсечь ненужные части таблицы. Плюс к этому, нет необходимости считывать некоторые колонки, так как они не идут на выход в случае select count(*) from (some), т.е. по памяти запрос будет работать тоже существенно лучше.

В общем случае — согласен, расчитывать на это не стоит. К примеру у MySQL стандартный оптимизатор достаточно простенький и многого не умеет.

И еще хочу добавить,
SELECT COUNT(*) FROM (<query>) A не отработает если мы имеет query виды <select expr> order by <columns,>. По крайней мере, по стандарту, order by должен всегда быть в конце запроса. Другое дело, что например MS SQL в данном случае уходит от стандарта и позволяет делать order by даже в подзапросах (это там понадобилось для поддержки ключевого слова top, так как top имеет смысл когда порядок записей известен). Но, опять же, в общем случае order by в подзапросах не поддерживается.
Re[5]: [OLEDB ] Количество записей в запросе и жуткие тормоз
От: MasterZiv СССР  
Дата: 17.10.08 09:00
Оценка:
Disappear wrote:

> По индексу количесто записей известно точно.

> Знаю точно, что вот эта СУБД (www.qdtechnology.com
> <http://www.qdtechnology.com>) это умеет. Знаю, собственно потому, что
> сам писал ее оптимизатор.

Увы, нет. Далеко не во всех СУБД.
У вас работают разные транзакции, для них видно
разное кол-во записей.

Но вы правы, в вашей СУБД — да.

"QD provides safe 24/7 read-only database access anytime and anywhere."

Ключевое слово — read-only.
Posted via RSDN NNTP Server 2.1 beta
Re[6]: [OLEDB ] Количество записей в запросе и жуткие тормоз
От: Disappear  
Дата: 17.10.08 09:07
Оценка:
Здравствуйте, MasterZiv, Вы писали:

MZ>Disappear wrote:


MZ>Ключевое слово — read-only.


А что мешает внутри блокирующей тратзакции сделать то же самое?
Re[5]: [OLEDB ] Количество записей в запросе и жуткие тормоз
От: Роман Дубров Украина Я@Blogspot
Дата: 17.10.08 09:08
Оценка:
Disappear пишет:

> SELECT COUNT(*) FROM (<query>) A не отработает если мы имеет query виды

> <select expr> order by <columns,>. По крайней мере, по стандарту, order
> by должен всегда быть в конце запроса. Другое дело, что например MS SQL

MySQL тоже только что проглотил вот такое и даже не поперхнулся. Видимо
по тем же причинам.
SELECT * FROM (
SELECT * FROM `counter_hits` ORDER BY `visitor_ip` LIMIT 10 , 10
) aaa
ORDER BY `datetime` DESC


--
np: [foobar2000] not started
Posted via RSDN NNTP Server 2.1 beta
http://www.linkedin.com/in/romandubrov .::. http://roman-dubrov.blogspot.com/ .::. http://www.flickr.com/photos/romandubrov/
Re[7]: [OLEDB ] Количество записей в запросе и жуткие тормоз
От: MasterZiv СССР  
Дата: 17.10.08 14:38
Оценка:
Disappear wrote:

> А что мешает внутри блокирующей тратзакции сделать то же самое?


Можно. можно заблокировать всю таблицу и радоваться, что у тебя --
фиксированное число строк в таблице. Только вот СУБД все борются
как раз за обратное.
Posted via RSDN NNTP Server 2.1 beta
Re[4]: [OLEDB ] Количество записей в запросе и жуткие тормоз
От: andy_84 Россия  
Дата: 20.10.08 05:33
Оценка:
Здравствуйте, Disappear, Вы писали:

>Парсить не нужно, а приделывать очень просто.

>SELECT COUNT(*) FROM (<any query>) A
>Оптимизатор любой адекватной СУБД это проглотит.

У SQL Server оптимизатор это не проглотил. Я набросал такой запросец, и сидел ждал, пока сервер считал кол-во строк вложенного запроса.
Re[4]: [OLEDB ] Количество записей в запросе и жуткие тормоз
От: andy_84 Россия  
Дата: 20.10.08 05:37
Оценка:
Здравствуйте, Nonmanual Worker, Вы писали:

NW>Здравствуйте, andy_84, Вы писали:


_>>Попробую сейчас сделать через IMultipleResults, мож че получится


NW>Должно получится.


Ну собственно, сделал я через этот IMultipleResults: выполнил "SELECT * FROM Table_name; SELECT @@ROWCOUNT as row_count", вызвал GetNextResult() и сидел ждал, пока не были пройдены все записи, возвращенные первым запросом.
Re[5]: [OLEDB ] Количество записей в запросе и жуткие тормоз
От: Nonmanual Worker  
Дата: 20.10.08 06:04
Оценка:
Здравствуйте, andy_84, Вы писали:

_>У SQL Server оптимизатор это не проглотил.


Нет, SQL Server оптимизатор это проглотил, но долго жевал

_>Я набросал такой запросец, и сидел ждал, пока сервер считал кол-во строк вложенного запроса.


Подставьте в свой оригинальный запрос COUNT(*) вместо списка полей, выполните (если выполнится), и сравните с тем временем, что вы получили. Если совпадает — то оптимизатор работает хорошо в силу своих возможностей, если получится что новое время значительно меньше — значит оптимизатор тупит.

З.Ы. Желательно пишите время выполнения запросов.
Re[6]: [OLEDB ] Количество записей в запросе и жуткие тормоз
От: andy_84 Россия  
Дата: 21.10.08 04:58
Оценка:
Здравствуйте, Nonmanual Worker, Вы писали:

NW>Здравствуйте, andy_84, Вы писали:


_>>У SQL Server оптимизатор это не проглотил.


NW>Нет, SQL Server оптимизатор это проглотил, но долго жевал


_>>Я набросал такой запросец, и сидел ждал, пока сервер считал кол-во строк вложенного запроса.


NW>Подставьте в свой оригинальный запрос COUNT(*) вместо списка полей, выполните (если выполнится), и сравните с тем временем, что вы получили. Если совпадает — то оптимизатор работает хорошо в силу своих возможностей, если получится что новое время значительно меньше — значит оптимизатор тупит.


NW>З.Ы. Желательно пишите время выполнения запросов.


Щас еще раз все внимательно проверил — действительно, "SELECT COUNT(*) FROM (<any query>) A" работает с удовлетворительной для меня скоростью (видимо, в первый раз невнимательно провел эксперимент).
Так что большое спасибо тов. Disappear и всем кто откликнулся.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.