我有这个命令
using (FbCommand cmd = new FbCommand(@"SELECT MIN(STAVKA.TREN_STANJE) FROM STAVKA RIGHT OUTER JOIN DOKUMENT ON STAVKA.VRDOK = DOKUMENT.VRDOK AND STAVKA.BRDOK = DOKUMENT.BRDOK WHERE(STAVKA.MAGACINID = @MID) AND(STAVKA.ROBAID = @RID) AND(DOKUMENT.FLAG < 2)", con))
{
cmd.Parameters.AddWithValue("@MID", magacinId);
cmd.Parameters.Add("@RID", FbDbType.Integer);
foreach(Int_Double stavka in stavkePocetnogStanjaSaKolicinama)
{
cmd.Parameters["@RID"].Value = stavka._int;
using (FbDataReader dr = cmd.ExecuteReader())
{
if (dr.Read())
{
double v = (dr[0] is DBNull) ? 0 : Convert.ToDouble(dr[0]);
double t = stavka._double;
if (smanjuj && !povecavaj)
{
if (v >= 0)
stavka._double -= v;
}
else if (smanjuj && povecavaj)
stavka._double -= v;
else if (!smanjuj && povecavaj)
{
if (v < 0)
stavka._double -= v;
}
else
{
MessageBox.Show("Doslo je do greske! - SvediPocetnoStanjeNaMinimum");
return;
}
}
}
}
}
SQL语句的位置是:
SELECT MIN(STAVKA.TREN_STANJE)
FROM STAVKA
RIGHT OUTER JOIN DOKUMENT
ON STAVKA.VRDOK = DOKUMENT.VRDOK AND STAVKA.BRDOK = DOKUMENT.BRDOK
WHERE (STAVKA.MAGACINID = @MID)
AND (STAVKA.ROBAID = @RID)
AND (DOKUMENT.FLAG < 2)
问题是using (FbDataReader dr = cmd.ExecuteReader())
需要大约3-4秒才能运行,如果几次运行它就没问题,但需要运行大约4k次,这是16k秒(4小时)
这两个表的工作原理如下:
我有一个文档(DOKUMENT
)是一行,它有多个项目STAVKA
),它们与DOKUMENT
相关联(具有文档类型(VRDOK
)和文件编号(BRDOK
))。
现在,对于每个项目STAVKA.ROBAID
),我选择STAVKA.TREN_STANJE
),但DOCUMENT.FLAG
包含STAVKA
必须flag < 2
示例:
STAVKA TABLE
STAVKAID | VRDOK | BRDOK | TREN_STANJE | ROBAID |
1 | 1 | 10 | 6 | 3 |
2 | 1 | 14 | 12 | 3 |
3 | 1 | 18 | 3 | 3 |
4 | 1 | 21 | 8 | 3 |
5 | 1 | 23 | 7 | 3 |
DOKUMENT TABLE
VRDOK | BRDOK | FLAG
1 | 10 | 1
1 | 14 | 3
1 | 18 | 1
1 | 21 | 1
1 | 23 | 4
因此,当我运行SQL语句时,需要从该文档的MIN(TREN_STANJE)
WHERE STAVKA
但ROBAID = @RID (3 in this case)
中选择FLAG
(因为您可以看到{{1}中的相同列}}和DOKUMENT
)必须为STAVKA
我怎么能加快速度呢?
< 2
表的结构是:
STAVKA
CREATE TABLE "STAVKA"
(
"STAVKAID" INTEGER NOT NULL,
"VRDOK" SMALLINT NOT NULL,
"BRDOK" INTEGER NOT NULL,
"MAGACINID" SMALLINT NOT NULL,
"ROBAID" INTEGER NOT NULL,
"VRSTA" SMALLINT,
"NAZIV" VARCHAR(50),
"NABCENSAPOR" NUMERIC(15,4),
"FAKTURNACENA" NUMERIC(15,4),
"NABCENABT" DOUBLE PRECISION,
"TROSKOVI" NUMERIC(15,4),
"NABAVNACENA" NUMERIC(15,4) NOT NULL,
"PRODCENABP" NUMERIC(15,4) NOT NULL,
"KOREKCIJA" DOUBLE PRECISION,
"PRODAJNACENA" NUMERIC(15,2) NOT NULL,
"DEVIZNACENA" NUMERIC(15,4) NOT NULL,
"DEVPRODCENA" NUMERIC(15,4),
"KOLICINA" NUMERIC(15,3) NOT NULL,
"NIVKOL" NUMERIC(15,3) NOT NULL,
"TARIFAID" VARCHAR(3),
"IMAPOREZ" SMALLINT,
"POREZ" NUMERIC(15,2) NOT NULL,
"RABAT" NUMERIC(15,2) NOT NULL,
"MARZA" NUMERIC(15,2) NOT NULL,
"TAKSA" NUMERIC(15,4),
"AKCIZA" NUMERIC(15,2),
"PROSNAB" NUMERIC(15,4) NOT NULL,
"PRECENA" NUMERIC(15,4) NOT NULL,
"PRENAB" NUMERIC(15,4) NOT NULL,
"PROSPROD" NUMERIC(15,4) NOT NULL,
"MTID" VARCHAR(10),
"PT" CHAR(1) NOT NULL,
"ZVEZDICA" VARCHAR(6),
"TREN_STANJE" NUMERIC(15,3),
"POREZ_ULAZ" NUMERIC(15,2) NOT NULL,
"SDATUM" DATE,
"DEVNABCENA" NUMERIC(15,4),
"POREZ_IZ" NUMERIC(15,2) NOT NULL,
"X4" NUMERIC(15,3),
"Y4" NUMERIC(15,3),
"Z4" NUMERIC(15,3),
"CENAPOAJM" NUMERIC(15,2),
"KGID" INTEGER,
CONSTRAINT "STAVKAPRIMARYKEY" PRIMARY KEY ("STAVKAID")
);
的结构是:
DOKUMENT
答案 0 :(得分:1)
此查询首先阅读DOKUMENT
表,然后阅读STAVKA
表。
如果过滤条件DOKUMENT.FLAG < 2
的选择性良好,则索引应该使其快速。当筛选的行小于表的5%时,选择性很好,理想情况下小于表的行的0.5%。为了获得良好的选择性,我将确保创建以下索引:
create index ix1_document on DOKUMENT (FLAG);
然后,它正在阅读表格STAVKA
。我假设该表已经有VRDOK
/ BRDOK
的索引,因为它可能是一个外键。但是,这还不足以使其更快。您需要在索引中加入MAGACINID
,ROBAID
和TREN_STANJE
:
create index ix1_stavka (VRDOK, BRDOK, MAGACINID, ROBAID, TREN_STANJE);
这个额外的索引会提高性能。
现在,如果您已经拥有这些索引,那么在SQL优化级别上您无法做更多的事情。
下一个选项是使用缓存。如果您运行查询4000次,也许您可以运行一次并在接下来的60秒内将结果保存在内存中。所有后续调用都将从内存中显示它,而不是再次运行查询...直到那些60秒过去,并且您认为结果“陈旧”。
另一种选择是使用内存数据库选项,如果在Firebird上可用,但我不确定。