На одной и той же машине из под одного и того же аккаунта запускаю один и тот же запрос. Запрос внутри ссылается на синонимы из других схем (если это имеет значение). Из-под тоада (и из-под sqlplus) выполнение происходит за пару секунд. Из-под своей программки, написанной на дотнете — дольше минуты.
выходил на dba — мало чем помогли, посмотрели в каком-то вебном туле — сказали мне, что в случае программки запрос начинает выполняться параллельно и потоки друг другу мешают — но мне что-то не верится в это плюс собственно вопрос в том, а почему так происходит.
была мысль, что из-за библиотечки для дотнета. System.Data.OracleClient считается устаревшей. Пробовал ODP.Net — лучше не стало.
также есть сейчас подозрение, что может быть разные home используются. Тоад показывает два:
SOFTWARE\ORACLE (Oracle Root)
ORACLE_HOME_NAME:
ORACLE_HOME:
ORACLE_SID:
NLS_LANG:
SQLPATH:
LOCAL:
Home directory does NOT exist!
Home is NOT valid!
SOFTWARE\ORACLE\KEY_V102030
ORACLE_HOME_NAME: v102030
ORACLE_HOME: C:\oracle\v102030
ORACLE_SID:
NLS_LANG: RUSSIAN_CIS.CL8MSWIN1251
SQLPATH: C:\oracle\v102030\dbs
LOCAL:
C:\oracle\v102030\Bin exists.
C:\oracle\v102030\Bin is in PATH.
Client DLL: C:\oracle\v102030\Bin\oci.dll
Client Version: 10.2.0.3.0Patch2
Home is valid.
хотя первый невалидный — не должен он использоваться. пробовал в реестре поставить oracle_home чтобы он стал валидным — ничего не изменилось.
запрос возвращает в частном случае три строки — т.е. распространённая причина, когда быстро вытягиваются только первые строки, а на самом деле всё очень долго — это не этот случай.
что может приводить к такому поведению? как продиагностировать точную причину? как это может быть, что сервер начинает себя вести по-разному в зависимости от клиента — ведь значит, что клиент должен какие-то переменные сессии выставлять, чтобы себя отличным сделать. где это посмотреть? dba могут определить только имя и id процесса.
P.S. попробовал ещё через Excel (ADODB.Connection msado28) и в дотнете, но через OdbcConnection — тоже быстро.
может быть всё что быстро работает — это через odbc? однако, тут почитал http://msdn.microsoft.com/en-us/library/ms810810.aspx oracle odbc вроде как устарела.
21.09.11 09:06: Перенесено модератором из '.NET' — TK
всю ночь не ем, весь день не сплю — устаю
Re: Oracle: TOAD и свой софт - разные планы запросов и скоро
Здравствуйте, Neco, Вы писали:
N>P.S. попробовал ещё через Excel (ADODB.Connection msado28) и в дотнете, но через OdbcConnection — тоже быстро. N>может быть всё что быстро работает — это через odbc? однако, тут почитал http://msdn.microsoft.com/en-us/library/ms810810.aspx oracle odbc вроде как устарела.
интересный нюанс обнаружился.
если заменить все переменные на константы — то запрос также выполняется очень быстро. так что тесты с sqlplus и экселем можно считать несостоявшимися — я не знаю как там переменные всавлять в запрос, поэтому сразу писал с константами.
Т.е. итого:
.Net System.Data.Oracle, .Net ODP.Net — медленно
Toad, .Net Odbc — быстро
.Net System.Data.Oracle (используя константы) — тоже быстро
всю ночь не ем, весь день не сплю — устаю
Re: Oracle: TOAD и свой софт - разные планы запросов и скоро
Здравствуйте, e.slyusar, Вы писали:
ES>Покажите код, как вы запускаете запрос!
namespace WindowsFormsApplication1 {
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e) {
var sw = new System.Diagnostics.Stopwatch();
sw.Start();
TestSystemData();
sw.Stop();
double system_data = sw.Elapsed.TotalSeconds;
sw.Reset();
sw.Start();
TestSystemDataNoParams();
sw.Stop();
double system_data_no_params = sw.Elapsed.TotalSeconds;
sw.Reset();
sw.Start();
TestOdbc();
sw.Stop();
double odbc = sw.Elapsed.TotalSeconds;
MessageBox.Show(string.Format("system.data {0}, system.data (no params) {1}, odbc {2}", system_data, system_data_no_params, odbc));
}
private void TestSystemData() {
using (var conn = new OracleConnection("Data Source=************; User ID=************;Password=*************;Persist Security Info=True;")) {
var sb = new StringBuilder();
sb.AppendLine("select t.id, t.name, t.is_active");
sb.AppendLine("from v_cost_center_master t ");
sb.AppendLine(" where (nvl(id, (select value from const where id_key='cc_for_orphans')) in (");
sb.AppendLine(" select cco.cost_center");
sb.AppendLine(" from v_cost_center_owners cco");
sb.AppendLine(" where cco.actual_owner_badge = :approver_badge");
sb.AppendLine(" and nvl(cco.doa_case_id_key,'-') <> :self_doa_partial");
sb.AppendLine(")");
sb.AppendLine(") and (id in (");
sb.AppendLine(" select org_cost_center");
sb.AppendLine(" from v_sb_snap_full");
sb.AppendLine(" where renewal_id=:renewal_id");
sb.AppendLine(")");
sb.AppendLine(")");
sb.AppendLine("order by t.id asc");
conn.Open();
using (var cmd = conn.CreateCommand()) {
cmd.CommandText = sb.ToString();
AddParam(cmd, "approver_badge", DbType.Int32, 10121543);
AddParam(cmd, "self_doa_partial", DbType.String, "self_doa_partial");
AddParam(cmd, "renewal_id", DbType.Int32, 6);
using (var adap = new OracleDataAdapter(cmd)) {
var tbl = new DataTable();
adap.Fill(tbl);
}
}
}
}
private void TestSystemDataNoParams() {
using (var conn = new OracleConnection("Data Source=**********; User ID=************;Password=************;Persist Security Info=True;")) {
var sb = new StringBuilder();
sb.AppendLine("select t.id, t.name, t.is_active");
sb.AppendLine("from v_cost_center_master t ");
sb.AppendLine(" where (nvl(id, (select value from const where id_key='cc_for_orphans')) in (");
sb.AppendLine(" select cco.cost_center");
sb.AppendLine(" from v_cost_center_owners cco");
sb.AppendLine(" where cco.actual_owner_badge = 10121543");
sb.AppendLine(" and nvl(cco.doa_case_id_key,'-') <> 'self_doa_partial'");
sb.AppendLine(")");
sb.AppendLine(") and (id in (");
sb.AppendLine(" select org_cost_center");
sb.AppendLine(" from v_sb_snap_full");
sb.AppendLine(" where renewal_id=6");
sb.AppendLine(")");
sb.AppendLine(")");
sb.AppendLine("order by t.id asc");
conn.Open();
using (var cmd = conn.CreateCommand()) {
cmd.CommandText = sb.ToString();
using (var adap = new OracleDataAdapter(cmd)) {
var tbl = new DataTable();
adap.Fill(tbl);
}
}
}
}
private void TestOdbc() {
using (var conn = new OdbcConnection("DSN=*****; UID=**********;PWD=************;")) {
var sb = new StringBuilder();
sb.AppendLine("select t.id, t.name, t.is_active");
sb.AppendLine("from v_cost_center_master t ");
sb.AppendLine(" where (nvl(id, (select value from const where id_key='cc_for_orphans')) in (");
sb.AppendLine(" select cco.cost_center");
sb.AppendLine(" from v_cost_center_owners cco");
sb.AppendLine(" where cco.actual_owner_badge = ?");
sb.AppendLine(" and nvl(cco.doa_case_id_key,'-') <> ?");
sb.AppendLine(")");
sb.AppendLine(") and (id in (");
sb.AppendLine(" select org_cost_center");
sb.AppendLine(" from v_sb_snap_full");
sb.AppendLine(" where renewal_id=?");
sb.AppendLine(")");
sb.AppendLine(")");
sb.AppendLine("order by t.id asc");
conn.Open();
using (var cmd = conn.CreateCommand()) {
cmd.CommandText = sb.ToString();
AddParam(cmd, "approver_badge", DbType.Int32, 10121543);
AddParam(cmd, "self_doa_partial", DbType.String, "self_doa_partial");
AddParam(cmd, "renewal_id", DbType.Int32, 6);
//cmd.Parameters.Add(CreateParam("approver_badge", DbType.Int32, 10121543));
//cmd.Parameters.Add(CreateParam("self_doa_partial", DbType.String, "self_doa_partial"));
//AddParam(cmd, "renewal_id", DbType.Int32, 6);int rez = cmd.ExecuteNonQuery();
}
}
}
private static void AddParam(IDbCommand cmd, string name, DbType type, object value) {
IDbDataParameter rez = cmd.CreateParameter();
rez.ParameterName = name;
rez.DbType = type;
rez.Value = value;
cmd.Parameters.Add(rez);
}
}
}
результаты
первого запуска: system.data 182.9845882, system.data (no params) 6.5533367, odbc 18.4702151
второго запуска: system.data 166.2260324, system.data (no params) 0.8451689, odbc 4.6515252
всю ночь не ем, весь день не сплю — устаю
Re: Oracle: TOAD и свой софт - разные планы запросов и скоро
т.е. сперва вызовите функцию TestSystemDataNoParams а за ней TestSystemData и вы будет тогда удивлены результатами.
Вообще при работе с базами данных, в частности с oracle установка подключения считается тяжелой операцией.
Глубоко внутри, что в System.Data.OracleClient, что в Oracle.DataAccess.Client, реализован пул коннектов.
При вызове первой функции создается коннект, выполняется запрос и коннект возвращается в пулл НО НЕ УНИЧТОЖАЕТСЯ!!!
При вызове второй функции коннект поднимается из пула и время на установление соединения с БД не тратится.
З.Ы. Вот отсюда и в TOAD такое время выполнения, ихмо он ходит уже по готовому коннекту.
З.З.Ы. И вообще, если работаете с Oracle то используйте Oracle Data Provider for .NET (http://www.oracle.com/technetwork/topics/dotnet/index-085163.html)
а если поверх ODP.NET использовать BlToolKit
Извиняюсь за много кода
using OracleConnection = Oracle.DataAccess.Client.OracleConnection;
using OracleDataAdapter = Oracle.DataAccess.Client.OracleDataAdapter;
static void Main(string[] args)
{
var sw = new System.Diagnostics.Stopwatch();
using (var conn = CreateConnection(_сonStr2))
{
using (var cmd = conn.CreateCommand())
{
cmd.CommandText = "select null from dual";
cmd.ExecuteNonQuery();
}
sw.Start();
TestSystemDataNoParams(conn);
sw.Stop();
double system_data_no_params = sw.Elapsed.TotalSeconds;
sw.Reset();
sw.Start();
TestSystemData(conn);
sw.Stop();
double system_data = sw.Elapsed.TotalSeconds;
sw.Reset();
sw.Start();
TestBlToolKit(conn);
sw.Stop();
double blToolKit_data1 = sw.Elapsed.TotalSeconds;
sw.Reset();
sw.Start();
TestBlToolKit(conn);
sw.Stop();
double blToolKit_data2 = sw.Elapsed.TotalSeconds;
sw.Reset();
sw.Start();
TestBlToolKit(conn);
sw.Stop();
double blToolKit_data3 = sw.Elapsed.TotalSeconds;
Console.WriteLine(string.Format("system.data {0}, system.data (no params) {1}, blToolKit {2}\\{3}\\{4}"
, system_data, system_data_no_params, blToolKit_data1, blToolKit_data2,
blToolKit_data3));
}
}
private static OracleConnection CreateConnection(string conStr)
{
var conn = new OracleConnection(conStr);
//Открываем коннект
conn.Open();
//принудительно инициализируем using (var cmd = conn.CreateCommand())
{
cmd.CommandText = "select null from dual";
cmd.ExecuteNonQuery();
}
return conn;
}
private static void TestBlToolKit(OracleConnection conn)
{
using (var db = new DbManager(conn))
{
db.SetCommand("select * from glossary where type = :pType"
, db.Parameter("pType", 123))
.ExecuteDataTable();
}
}
private static void TestSystemData(OracleConnection conn)
{
var sb = new StringBuilder();
sb.AppendLine("select * from glossary where type = :pType");
sb.AppendLine("order by 2 asc");
using (var cmd = conn.CreateCommand())
{
cmd.CommandText = sb.ToString();
AddParam(cmd, "pType", DbType.Int32, 123);
using (var adap = new OracleDataAdapter(cmd))
{
var tbl = new DataTable();
adap.Fill(tbl);
}
}
}
private static void TestSystemDataNoParams(OracleConnection conn)
{
var sb = new StringBuilder();
sb.AppendLine("select * from glossary where type = 123");
sb.AppendLine("order by 2 asc");
using (var cmd = conn.CreateCommand())
{
cmd.CommandText = sb.ToString();
using (var adap = new OracleDataAdapter(cmd))
{
var tbl = new DataTable();
adap.Fill(tbl);
}
}
}
private static void AddParam(IDbCommand cmd, string name, DbType type, object value)
{
IDbDataParameter rez = cmd.CreateParameter();
rez.ParameterName = name;
rez.DbType = type;
rez.Value = value;
cmd.Parameters.Add(rez);
}
Re[2]: Oracle: TOAD и свой софт - разные планы запросов и ск
Здравствуйте, e.slyusar, Вы писали:
ES>В предложном коде, поменяйте местами вызовы:
Спасибо за ответ, но более 150 секунд это слишком уж много для открытия соединения. ))
тем более я это всё заметил на продакшн коде, где пулы конечно используются.
но объективности ради, я конечно поменял местами, как Вы просили.
вот код:
вот результат:
system.data 170.6726251, system.data (no params) 9.7868333, odbc 16.0092746
т.е. ничего принципиально не поменялось.
ES>З.З.Ы. И вообще, если работаете с Oracle то используйте Oracle Data Provider for .NET (http://www.oracle.com/technetwork/topics/dotnet/index-085163.html)
как я писал в оригинальном сообщении — я тоже думал, что ODP.Net исправит ситуацию, но, к сожалению, не помогло. Он также долго думает, а по завершении этого долгого времени ещё и выдавал ошибку invalid number на одном из рабочих запросов.
вот счас добавил к тесту odp:
system.data 158.0326224, system.data (no params) 0.8253322, odbc 2.9505964, odp 165.9107353, odp no params 5.1539829
в порядке бреда запускал релиз-версии — безрезультатно.
system.data 170.0237713, system.data (no params) 1.2875285, odbc 3.4835377, odp 162.6703569, odp no params 1.2028065
ES>Извиняюсь за много кода
это ничего, спасибо ))
что меня убивает в этой ситуации, так это что наверняка ODBC использует нативную оракловую библиотеку — вопрос только "как он её использует?"...
всю ночь не ем, весь день не сплю — устаю
Re[2]: Oracle: TOAD и свой софт - разные планы запросов и ск
Здравствуйте, Neco, Вы писали:
N>если заменить все переменные на константы — то запрос также выполняется очень быстро. так что тесты с sqlplus и экселем можно считать несостоявшимися — я не знаю как там переменные всавлять в запрос, поэтому сразу писал с константами.
В базе для строк используется VARCHAR?
DbType.String — это NVARCHAR. Как с этим в Оракле — я не знаю, но в MSSQL в некоторых случаях делает CAST внутри предиката, поэтому если параметры не соответствуют -> получаем жуткую деградацию.
Re: Oracle: TOAD и свой софт - разные планы запросов и скоро
Здравствуйте, fddima, Вы писали:
F>Здравствуйте, Neco, Вы писали:
N>>если заменить все переменные на константы — то запрос также выполняется очень быстро. так что тесты с sqlplus и экселем можно считать несостоявшимися — я не знаю как там переменные всавлять в запрос, поэтому сразу писал с константами. F> В базе для строк используется VARCHAR? F> DbType.String — это NVARCHAR. Как с этим в Оракле — я не знаю, но в MSSQL в некоторых случаях делает CAST внутри предиката, поэтому если параметры не соответствуют -> получаем жуткую деградацию.
спасибо за версию — для верности просто убрал использование параметров строкового типа. а также попробовал запускать запрос с каждым из параметров по очереди (а остальные два оставлять константами). картина та же.
всю ночь не ем, весь день не сплю — устаю
Re[2]: Oracle: TOAD и свой софт - разные планы запросов и ск
Здравствуйте, e.slyusar, Вы писали:
ES>А какая у вас версия ODAC.NET? И какая версия СУБД?
ODAC112021Xcopy_32bit
СУБД 10.2.0.5.0
ES>в моем случае, тормозов с переменными нет (естественно на другой схеме данных)
на простых запросах этого тоже не наблюдается.
и даже больше.
внутри потрохов запроса используется вьюшка, которая смотрит на синоним из другой схемы. если я эту вьюшку заменяю эквивалентной таблицей, то всё ускоряется (что ожидаемо). а ещё такой нюанс вспомнился: в тоаде первоначально этот запрос тоже тормозил (правда не уверен что всё было настолько плохо — насколько помнится секунд двадцать висел) и чтобы соптимизировать его я хотел построить план запроса, на что получил ошибку типа "нет прав на нижележащие объекты". тогда я попросил dba дать нужные права на таблицы из зависимой схемы. они дали и запрос сразу стал выполняться быстрее.
т.е. я так понял, что у когда у аккаунта нет прав на статистику связанной схемы, то он может построить менее качественный план. с одной стороны бредово (движку-то СУБД должна быть доступна вся статистика, зачем идти от имени аккаунта...), ну да ладно — примем за данность.
но теперь-то я иду от аккаунта, у которого есть права. приложение и тоад работают из-под одного аккаунта.
всю ночь не ем, весь день не сплю — устаю
Re: Oracle: TOAD и свой софт - разные планы запросов и скоро
Toad:
SELECT STATEMENT () {null}
TEMP TABLE TRANSFORMATION () {null}
PX COORDINATOR () {null}
PX SEND (QC (RANDOM)) :TQ10002
LOAD AS SELECT () COST_CENTER_MASTER
PX RECEIVE () {null}
PX SEND (ROUND-ROBIN) :TQ10001
VIEW () {null}
SORT (UNIQUE) {null}
PX RECEIVE () {null}
PX SEND (HASH) :TQ10000
UNION-ALL () {null}
PX BLOCK (ITERATOR {null}
TABLE ACCESS (FUL COST_CENTER_MASTER
PX BLOCK (ITERATOR {null}
TABLE ACCESS (FUL COST_CENTER_MASTER
PX COORDINATOR () {null}
PX SEND (QC (ORDER)) :TQ20012
SORT (ORDER BY) {null}
PX RECEIVE () {null}
PX SEND (RANGE) :TQ20011
HASH JOIN (BUFFERED) {null}
PX RECEIVE () {null}
PX SEND (HASH) :TQ20009
VIEW () VW_NSO_2
HASH (UNIQUE) {null}
PX RECEIVE () {null}
PX SEND (HASH) :TQ20007
BUFFER (SORT) {null}
NESTED LOOPS (O {null}
NESTED LOOPS ( {null}
NESTED LOOPS {null}
NESTED LOOPS {null}
NESTED LOOP {null}
NESTED LOO {null}
NESTED LO {null}
NESTED L {null}
NESTED {null}
NESTED {null}
NESTE {null}
HASH {null}
BUF {null}
PX {null}
P :TQ20002
SB_SNAP
PX {null}
PX :TQ20005
H {null}
{null}
:TQ20003
{null}
COST_CENTER_MASTER
{null}
{null}
:TQ20001
{null}
CONST
PK_CONST
PEOPLE_MASTER_SNAP
INDE PK_STATUS
TABLE SB_ACTION
INDE PK_SB_ACTION
TABLE SB_ACTION
INDEX PK_SB_ACTION
TABLE A PEOPLE_MASTER_SNAP
INDEX PK_PEOPLE_MASTER_SNAP
TABLE AC PEOPLE_MASTER_SNAP
INDEX ( PK_PEOPLE_MASTER_SNAP
TABLE ACC PEOPLE_MASTER_SNAP
INDEX (U PK_PEOPLE_MASTER_SNAP
TABLE ACCE PEOPLE_MASTER_SNAP
INDEX (UN PK_PEOPLE_MASTER_SNAP
TABLE ACCES PEOPLE_MASTER_SNAP
INDEX (UNI PK_PEOPLE_MASTER_SNAP
TABLE ACCESS PEOPLE_MASTER_SNAP
INDEX (UNIQ PK_PEOPLE_MASTER_SNAP
VIEW PUSHED P V_PEOPLE_MASTER
NESTED LOOPS {null}
NESTED LOOP {null}
NESTED LOO {null}
NESTED LO {null}
NESTED L {null}
NESTED {null}
NESTED {null}
TABLE PEOPLE_MASTER_SNAP
INDE PK_PEOPLE_MASTER_SNAP
TABLE PEOPLE_MASTER_SNAP
INDE PK_PEOPLE_MASTER_SNAP
TABLE COST_CENTER_MASTER
INDEX PK_COST_CENTER_MASTER
TABLE A PEOPLE_MASTER_SNAP
INDEX PK_PEOPLE_MASTER_SNAP
TABLE AC PEOPLE_MASTER_SNAP
INDEX ( PK_PEOPLE_MASTER_SNAP
TABLE ACC PEOPLE_MASTER_SNAP
INDEX (U PK_PEOPLE_MASTER_SNAP
TABLE ACCE PEOPLE_MASTER_SNAP
INDEX (UN PK_PEOPLE_MASTER_SNAP
TABLE ACCES PEOPLE_MASTER_SNAP
INDEX (UNI PK_PEOPLE_MASTER_SNAP
VIEW PUSHED PR V_PEOPLE_MASTER
NESTED LOOPS {null}
NESTED LOOPS {null}
NESTED LOOP {null}
NESTED LOO {null}
NESTED LO {null}
NESTED L {null}
NESTED {null}
TABLE PEOPLE_MASTER_SNAP
INDEX PK_PEOPLE_MASTER_SNAP
TABLE PEOPLE_MASTER_SNAP
INDEX PK_PEOPLE_MASTER_SNAP
TABLE A COST_CENTER_MASTER
INDEX PK_COST_CENTER_MASTER
TABLE AC PEOPLE_MASTER_SNAP
INDEX ( PK_PEOPLE_MASTER_SNAP
TABLE ACC PEOPLE_MASTER_SNAP
INDEX (U PK_PEOPLE_MASTER_SNAP
TABLE ACCE PEOPLE_MASTER_SNAP
INDEX (UN PK_PEOPLE_MASTER_SNAP
TABLE ACCES PEOPLE_MASTER_SNAP
INDEX (UNI PK_PEOPLE_MASTER_SNAP
TABLE ACCESS PEOPLE_MASTER_SNAP
INDEX (UNIQ PK_PEOPLE_MASTER_SNAP
PX RECEIVE () {null}
PX SEND (HASH) :TQ20010
NESTED LOOPS () {null}
BUFFER (SORT) {null}
PX RECEIVE () {null}
PX SEND (BROADCAS :TQ20008
VIEW () VW_NSO_1
HASH (UNIQUE) {null}
PX RECEIVE () {null}
PX SEND (HASH :TQ20006
VIEW () V_COST_CENTER_OWNERS
SORT (UNIQU {null}
PX RECEIVE {null}
PX SEND ( :TQ20004
UNION-AL {null}
FILTER {null}
HASH J {null}
BUFFE {null}
PX R {null}
PX :TQ20000
VI {null}
N {null}
PK_DOA_COST_CENTER
DOA
PK_DOA
VIEW {null}
PX B {null}
TAB SYS_TEMP_0FD9D6EFB_216989B7
FILTER {null}
VIEW ( {null}
PX BL {null}
TABL SYS_TEMP_0FD9D6EFB_216989B7
PX BLOCK (ITERATOR) {null}
TABLE ACCESS (FULL COST_CENTER_MASTER
TABLE ACCESS (BY CONST
INDEX (UNIQUE SC PK_CONST
выделенной жирным части в варианте с дотнетом нет. остальное выглядит похоже.
всю ночь не ем, весь день не сплю — устаю
Re[3]: Oracle: TOAD и свой софт - разные планы запросов и ск
От:
Аноним
Дата:
14.09.11 12:47
Оценка:
N> sb.AppendLine(" where (nvl(id, (select value from const where id_key='cc_for_orphans')) in ("); N> sb.AppendLine(" select cco.cost_center"); N> sb.AppendLine(" from v_cost_center_owners cco"); N> sb.AppendLine(" where cco.actual_owner_badge = :approver_badge"); N> sb.AppendLine(" and nvl(cco.doa_case_id_key,'-') <> :self_doa_partial
Так верстают только сами знаете кто. nvl(field) = :var — это нет. nvl(id) = — это совсем нет.
Напиши запрос нормально и всё само пройдёт (имхо).
Re[2]: Oracle: TOAD и свой софт - разные планы запросов и ск
Здравствуйте, Аноним, Вы писали:
N>> sb.AppendLine(" where (nvl(id, (select value from const where id_key='cc_for_orphans')) in ("); N>> sb.AppendLine(" select cco.cost_center"); N>> sb.AppendLine(" from v_cost_center_owners cco"); N>> sb.AppendLine(" where cco.actual_owner_badge = :approver_badge"); N>> sb.AppendLine(" and nvl(cco.doa_case_id_key,'-') <> :self_doa_partial А>Так верстают только сами знаете кто.
— кто же ходит за мёдом с воздушным шаром?
— я хожу
А>nvl(field) = :var — это нет. nvl(id) = — это совсем нет. А>Напиши запрос нормально и всё само пройдёт (имхо).
ну тоад считает, что запрос написан нормально.
собственно суть моего вопроса не в том, как ускорить выполение запроса, а почему поведение разное из-под тоада и из под кода.
всю ночь не ем, весь день не сплю — устаю
Re[3]: Oracle: TOAD и свой софт - разные планы запросов и ск
Здравствуйте, Аноним, Вы писали:
А>По твоему план должен так выглядеть? Не кажется тебе странным этот набор строк?
мне кажутся странными только твои комментарии
всю ночь не ем, весь день не сплю — устаю
Re[4]: Oracle: TOAD и свой софт - разные планы запросов и ск
От:
Аноним
Дата:
14.09.11 13:38
Оценка:
Здравствуйте, Neco, Вы писали:
N>Здравствуйте, Аноним, Вы писали:
А>>По твоему план должен так выглядеть? Не кажется тебе странным этот набор строк? N>мне кажутся странными только твои комментарии
Поясню. Ты выдал в аутпут текстовый мусор. Сообщив, что как видите планы совпадают. Это слегка настораживает.
Вот я и поинтересовался,что такое по твоему план запроса и как он должен выглядеть.
(я не знаю может ты в уме склеиваешь как надо строки и тебе всё понятно).
Re[5]: Oracle: TOAD и свой софт - разные планы запросов и ск
Здравствуйте, Аноним, Вы писали:
А>>>По твоему план должен так выглядеть? Не кажется тебе странным этот набор строк? N>>мне кажутся странными только твои комментарии А>Поясню. Ты выдал в аутпут текстовый мусор. Сообщив, что как видите планы совпадают. Это слегка настораживает. А>Вот я и поинтересовался,что такое по твоему план запроса и как он должен выглядеть. А>(я не знаю может ты в уме склеиваешь как надо строки и тебе всё понятно).
ок, какая именно информация из плана запроса нужна? или если есть под рукой готовый sql, который вытягивает инфу так, как надо — выложи сюда, я прогоню и покажу отчёт в том виде, каком тебе удобно.
просто я сам в дебрях планов запроса не разбираюсь. но два плана на идентичность сравнить могу (чисто по форме лесенки и началу строк).
всю ночь не ем, весь день не сплю — устаю
Re: Oracle: TOAD и свой софт - разные планы запросов и скоро
SELECT T.ID, T.NAME, T.IS_ACTIVE
FROM V_COST_CENTER_MASTER T
WHERE
(
NVL(T.ID, (SELECT VALUE FROM CONST WHERE ID_KEY='CC_FOR_ORPHANS') ) /* 1 */IN (
SELECT CCO.COST_CENTER FROM V_COST_CENTER_OWNERS CCO
WHERE CCO.ACTUAL_OWNER_BADGE = :APPROVER_BADGE
AND NVL(CCO.DOA_CASE_ID_KEY,'-') <> :SELF_DOA_PARTIAL /* 2 */
)
)
AND
(
ID IN ( SELECT ORG_COST_CENTER FROM V_SB_SNAP_FULL WHERE RENEWAL_ID= :RENEWAL_ID ) /* 3 */
)
ORDER BY T.ID ASC
Уважаемый, пишите запросы крупным почерком — берегите глаза чекистов.
дальше комментарии по запросу —
1. поменять на константу, потому как оно и будет константой, это уберет NVL и поможет оптимайзеру
2. переписать по человечески, хотя бы как where DOA_CASE_ID_KEY IS NOT NULL AND DOA_CASE_ID_KEY <> :SELF_DOA_PARTIAL
3. сделайте union на первую и вторую часть условия и по этому юниону уже select from cost_center_master where id in ( select a.id union all select b.id).
Здравствуйте, B0rG, Вы писали:
BG>Уважаемый, пишите запросы крупным почерком — берегите глаза чекистов.
переписал вот так:
SELECT T.ID, T.NAME, T.IS_ACTIVE
FROM V_COST_CENTER_MASTER T
WHERE
(
T.ID
IN (
SELECT TO_CHAR(NVL(CCO.COST_CENTER,:DEFAULT_CC))
FROM V_COST_CENTER_OWNERS CCO
WHERE CCO.ACTUAL_OWNER_BADGE = :APPROVER_BADGE
AND (CCO.DOA_CASE_ID_KEY IS NULL OR CCO.DOA_CASE_ID_KEY <> :SELF_DOA_PARTIAL)
INTERSECT
SELECT ORG_COST_CENTER FROM V_SB_SNAP_FULL WHERE RENEWAL_ID= :RENEWAL_ID
)
)
ORDER BY T.ID ASC
BG>дальше комментарии по запросу — BG>1. поменять на константу, потому как оно и будет константой, это уберет NVL и поможет оптимайзеру
заменил переменной. в приниципе да — могу вычислять это перед запросом (лишний поход в базу, ну да фиг с ним).
BG>2. переписать по человечески, хотя бы как where DOA_CASE_ID_KEY IS NOT NULL AND DOA_CASE_ID_KEY <> :SELF_DOA_PARTIAL
это меняет суть запроса. с AND там не получается — надо брать либо когда слева null, либо когда значения равны.
BG>3. сделайте union на первую и вторую часть условия и по этому юниону уже select from cost_center_master where id in ( select a.id union all select b.id).
это тоже меняет суть запроса. тогда выбираются и те и другие, а надо тех, которые и там и там. заменил на intersect.
BG>так же поможет следующая инфа
VIEW v_cost_center_master
Name Null? Type
----------------------------------------- -------- ----------------------------
ID NVARCHAR2
NAME VARCHAR2(90)
IS_ACTIVE NUMBER
CC_OWNER1_BADGE NUMBER(8)
CC_OWNER1_NAME VARCHAR2(40)
CC_OWNER2_BADGE NUMBER(8)
CC_OWNER2_NAME VARCHAR2(40)
VIEW v_cost_center_owners
Name Null? Type
----------------------------------------- -------- ----------------------------
COST_CENTER NVARCHAR2
RL_OWNER_BADGE NUMBER(8)
ACTUAL_OWNER_BADGE NUMBER
DUE_TO_DELEGATION NUMBER
DOA_CASE_ID_KEY NVARCHAR2
DIRECT NUMBER
VIEW v_sb_snap_full
Name Null? Type
----------------------------------------- -------- ----------------------------
ID NOT NULL NUMBER
RENEWAL_ID NOT NULL NUMBER
EMP_BADGE NOT NULL NUMBER
ORG_COST_CENTER_SNAP NOT NULL NVARCHAR2
STATUS_ID_KEY NOT NULL NVARCHAR2
STATUS_NAME NVARCHAR2
CONFIRM_ACTION_ID NUMBER
CONFIRM_ACTION_COMMENT NVARCHAR2
CONFIRMATION_DATE DATE
CONFIRMER_BADGE NUMBER
CONFIRMER_NAME VARCHAR2(136)
APPROVE_ACTION_ID NUMBER
APPROVE_ACTION_COMMENT NVARCHAR2
APPROVAL_DATE DATE
APPROVER_BADGE NUMBER
APPROVER_NAME VARCHAR2(136)
EMP_NAME VARCHAR2(136)
EMP_SEARCH_TYPE VARCHAR2(9)
EMP_TYPE VARCHAR2(9)
EMP_USER_ID VARCHAR2(255)
EMP_COST_CENTER VARCHAR2(36)
EMP_COST_CENTER_NAME VARCHAR2(90)
ORG_COST_CENTER VARCHAR2(1500)
EMP_HOME_COMPANY_NAME VARCHAR2(120)
LINE_SUP1_AB_NUMBER NUMBER(8)
LINE_SUP1_NORM_ENG_FULL_NAME VARCHAR2(136)
LINE_SUP2_AB_NUMBER NUMBER(8)
LINE_SUP2_NORM_ENG_FULL_NAME VARCHAR2(136)
немного поясню вопрос:
1. код SQL генерируется. причём различные участки повторно используются, что собственно и делает генерацию нужной — замена статическим оптимизированным SQL-выражением приведёт к многочисленным копи-пастам, чего не хотелось бы.
2. у меня уже есть workaround — если я делаю вьюшку материализованными представлениями, то всё начинает летать как в тоаде, так и в софте. вьюшки обновляются раз в сутки ночью — можно себе это позволить. другой workaround — внутри одной из вьюшек добавить хинт NO_USE_HASH. тогда запрос начинает выполняться за 6 секунд в обоих случаях (toad vs .net).
3. вопрос не в том, как улучшить SQL-запрос или вьюшки, а в том, как добиться одинакового поведения и узнать почему оно собственно рознится. почему принимая запрос из toad'а оракл выполняет TEMP TABLE TRANSFORMATION, а принимая тот же запрос из дотнета, почему-то не хочет.
всю ночь не ем, весь день не сплю — устаю
Re[2]: Oracle: TOAD и свой софт - разные планы запросов и ск