473,598 Members | 3,344 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Is there a way to check the order in which SET INTEGRITY needs to be applied?

Is there a way to check the order in which SET INTEGRITY needs to be
applied? This would be for a script with a dynamic list of TABLEs.

B.

Nov 30 '06 #1
16 5650

Brian Tkatch wrote:
Is there a way to check the order in which SET INTEGRITY needs to be
applied? This would be for a script with a dynamic list of TABLEs.

B.
Not exactly the same problem (I use it to archive old data, and need to
delete from the tables in a certain order to not violate foreign keys),
but the solution should work I think. First I select "independen t
tables in the set of tables, and the follow foreign keys recursively.
Since a table might occur several times in the graph, I choose the
largest level for each table. Finally I sort the tables according to
the level. As mentioned it is not exactly what you want, but it should
give you some ideas (Not fully tested though):

#!/bin/sh

ADMISSION_ROUND =$1

if [ "x${ADMISSION_R OUND}" = "x" ]; then
prog=`basename $0`
echo "Usage: $prog <admissionround _id>"
exit 1
fi

iter="with t (tabschema, tabname, level) as ( \
values ('NYA', 'ADMISSION_ROUN D', 0) \
union all \
select c.tabschema, c.tabname, 0 \
from syscat.columns c \
where c.colname = 'ADMISSIONROUND _ID' \
and c.tabschema = 'NYA' \
and not exists ( \
select 1 from syscat.referenc es r \
where (r.tabschema, r.tabname) = (c.tabschema,
c.tabname) \
and fk_colnames <'ADMISSIONROUN D_ID' \
) \
union all \
select r.tabschema, r.tabname, level+1 \
from t, syscat.referenc es r \
where (t.tabschema, t.tabname) = (r.reftabschema , r.reftabname)
\
and r.tabschema = 'NYA' \
and level < 100 \
), res(tabname,lev el) as ( \
select tabname, max(level) as level from t \
group by tabname \
) select x.tabname from res x, syscat.tables t \
where ('NYA', x.tabname) = (t.tabschema, t.tabname) \
and t.type = 'T' \
order by level desc"

db2 connect to ltjn

for t in `db2 -x "$iter"`; do
echo "Archiving $t ..."
db2 -v "export to $t.ixf of ixf select * from nya.$t \
where admissionround_ id = '${ADMISSION_RO UND}'"
if [ $? -ne 0 ]; then
echo "Failure"
exit 1
fi
# db2 +c -v "delete from nya.$t \
db2 -v "delete from nya.$t \
where admissionround_ id = '${ADMISSION_RO UND}'"
if [ $? -gt 1 ]; then
echo "Failure"
exit 1
fi
# db2 rollback
done

tar cvfz ${ADMISSION_ROU ND}-archive.tgz *.ixf /dev/null 2>&1

Nov 30 '06 #2
Lennart wrote:
Brian Tkatch wrote:
Is there a way to check the order in which SET INTEGRITY needs to be
applied? This would be for a script with a dynamic list of TABLEs.

B.

Not exactly the same problem (I use it to archive old data, and need to
delete from the tables in a certain order to not violate foreign keys),
but the solution should work I think. First I select "independen t
tables in the set of tables, and the follow foreign keys recursively.
Since a table might occur several times in the graph, I choose the
largest level for each table. Finally I sort the tables according to
the level. As mentioned it is not exactly what you want, but it should
give you some ideas (Not fully tested though):

#!/bin/sh

ADMISSION_ROUND =$1

if [ "x${ADMISSION_R OUND}" = "x" ]; then
prog=`basename $0`
echo "Usage: $prog <admissionround _id>"
exit 1
fi

iter="with t (tabschema, tabname, level) as ( \
values ('NYA', 'ADMISSION_ROUN D', 0) \
union all \
select c.tabschema, c.tabname, 0 \
from syscat.columns c \
where c.colname = 'ADMISSIONROUND _ID' \
and c.tabschema = 'NYA' \
and not exists ( \
select 1 from syscat.referenc es r \
where (r.tabschema, r.tabname) = (c.tabschema,
c.tabname) \
and fk_colnames <'ADMISSIONROUN D_ID' \
) \
union all \
select r.tabschema, r.tabname, level+1 \
from t, syscat.referenc es r \
where (t.tabschema, t.tabname) = (r.reftabschema , r.reftabname)
\
and r.tabschema = 'NYA' \
and level < 100 \
), res(tabname,lev el) as ( \
select tabname, max(level) as level from t \
group by tabname \
) select x.tabname from res x, syscat.tables t \
where ('NYA', x.tabname) = (t.tabschema, t.tabname) \
and t.type = 'T' \
order by level desc"

db2 connect to ltjn

for t in `db2 -x "$iter"`; do
echo "Archiving $t ..."
db2 -v "export to $t.ixf of ixf select * from nya.$t \
where admissionround_ id = '${ADMISSION_RO UND}'"
if [ $? -ne 0 ]; then
echo "Failure"
exit 1
fi
# db2 +c -v "delete from nya.$t \
db2 -v "delete from nya.$t \
where admissionround_ id = '${ADMISSION_RO UND}'"
if [ $? -gt 1 ]; then
echo "Failure"
exit 1
fi
# db2 rollback
done

tar cvfz ${ADMISSION_ROU ND}-archive.tgz *.ixf /dev/null 2>&1
Wow, that's bigger than the statement i wanted to see, like SET
INTEGRITY FOR <tableIMMEDIA TE CHECKED
AND_I_DO_MEAN_A LL_SO_FOLLOW_TH OSE_KEY_TREES *ehem* i mean: SET
INTEGRITY FOR <tableIMMEDIA TE CHECKED WITH CASCADE;

I'm going to look at what you wrote (thanx!). In the meanwhile, i came
up with another idea. The basic thought is that if SET INTEGRITY is run
on a list of TABLEs in a loop, and the loop runs once for each TABLE in
the list, even when it is in reverse order (which would be just my
luck) it's got to zap 'em all by the end.

Then i thought, maybe i could check the COUNT(*) WHERE Status = 'C'
(with an IN list) and just run it until it returns 0 (or it doesn't go
down between runs).

My question is, is your script faster or slower than my brute force
idea? :)

B.

Nov 30 '06 #3

Brian Tkatch wrote:
[...]
>
Wow, that's bigger than the statement i wanted to see, like SET
INTEGRITY FOR <tableIMMEDIA TE CHECKED
AND_I_DO_MEAN_A LL_SO_FOLLOW_TH OSE_KEY_TREES *ehem* i mean: SET
INTEGRITY FOR <tableIMMEDIA TE CHECKED WITH CASCADE;

I'm going to look at what you wrote (thanx!). In the meanwhile, i came
up with another idea. The basic thought is that if SET INTEGRITY is run
on a list of TABLEs in a loop, and the loop runs once for each TABLE in
the list, even when it is in reverse order (which would be just my
luck) it's got to zap 'em all by the end.
Problem is, the number of tables you will have to set integrity on
might increase. Assume you have table T with status C. If you set
integrity on it, you will have to set integrity on tables dependent of
it. So you might end up with

iteration table
1 T1
2 T2, T3, T4
3 T5, T6, T7, T8, T9
etc

If you are unlucky, you might end up setting integrity on each and
every table in the database (and some tables more than once).
Then i thought, maybe i could check the COUNT(*) WHERE Status = 'C'
(with an IN list) and just run it until it returns 0 (or it doesn't go
down between runs).
Something like (pseducode):

while (true)
for t in `db2 "select tabname from syscat.tables where status =
'C'"; do
db2 "set integrity ..."
done
# test if tables remain, if so break;
done
My question is, is your script faster or slower than my brute force
idea? :)
In general I would say that it is faster trying to figure out how to do
it in right order. On the other hand, if few people use the database at
the time of execution of the script, it might not be worth it. A brute
force solution should not take that long to implement, if that is not
fast enough, concider other things.

If you have access to python/perl or something similar, another option
is to build a graph from syscat.referenc es and use topological sort to
determine the order. I think I have some pythoncode lying around, drop
me a note if interested.

/Lennart

Nov 30 '06 #4
fwiw.

I have a shell script that does this brute force method for our
Database of some 300+ Tables and it works just fine i.e the overhead
trying to set integrity where it's not required is miinimal.

Brian Tkatch wrote:
My question is, is your script faster or slower than my brute force
idea? :)

B.
Dec 1 '06 #5
Lennart wrote:
Brian Tkatch wrote:
[...]

Wow, that's bigger than the statement i wanted to see, like SET
INTEGRITY FOR <tableIMMEDIA TE CHECKED
AND_I_DO_MEAN_A LL_SO_FOLLOW_TH OSE_KEY_TREES *ehem* i mean: SET
INTEGRITY FOR <tableIMMEDIA TE CHECKED WITH CASCADE;

I'm going to look at what you wrote (thanx!). In the meanwhile, i came
up with another idea. The basic thought is that if SET INTEGRITY is run
on a list of TABLEs in a loop, and the loop runs once for each TABLE in
the list, even when it is in reverse order (which would be just my
luck) it's got to zap 'em all by the end.

Problem is, the number of tables you will have to set integrity on
might increase. Assume you have table T with status C. If you set
integrity on it, you will have to set integrity on tables dependent of
it. So you might end up with

iteration table
1 T1
2 T2, T3, T4
3 T5, T6, T7, T8, T9
etc

If you are unlucky, you might end up setting integrity on each and
every table in the database (and some tables more than once).
Then i thought, maybe i could check the COUNT(*) WHERE Status = 'C'
(with an IN list) and just run it until it returns 0 (or it doesn't go
down between runs).

Something like (pseducode):

while (true)
for t in `db2 "select tabname from syscat.tables where status =
'C'"; do
db2 "set integrity ..."
done
# test if tables remain, if so break;
done
My question is, is your script faster or slower than my brute force
idea? :)

In general I would say that it is faster trying to figure out how to do
it in right order. On the other hand, if few people use the database at
the time of execution of the script, it might not be worth it. A brute
force solution should not take that long to implement, if that is not
fast enough, concider other things.

If you have access to python/perl or something similar, another option
is to build a graph from syscat.referenc es and use topological sort to
determine the order. I think I have some pythoncode lying around, drop
me a note if interested.

/Lennart
Wow, you're amazing. I appreciate you taking the time to help me.
Problem is, the number of tables you will have to set integrity on
might increase. Assume you have table T with status C. If you set
integrity on it, you will have to set integrity on tables dependent of it.
Because of that, i figured i didn't want to mess. I just want he script
to SET INTEGRITY on its own TABLEs, and on nothing else. So, if the
number increases outside of the listed TABLEs, the process itself is
flawed.

Now to that pseudocode:

x1=`db2 "select COUNT(*) from syscat.tables where status =
'C' AND (TabSchema, TabName) IN (<schema and tables in file>)"
while (read schema table)
do
db2 "set integrity ..."
x2=`db2 "select COUNT(*) from syscat.tables where status =
'C' AND (TabSchema, TabName) IN (<schema and tables in file>)" ;
if ! (x2 < x1) break; else x1=x2;
done < file

It could be fancier by checking the status of each table afterwards and
see if it got reset. Plus, set integrity can do all the tables in the
same statement.
In general I would say that it is faster trying to figure out how to do
it in right order. On the other hand, if few people use the database at
the time of execution of the script, it might not be worth it. A brute
force solution should not take that long to implement, if that is not
fast enough, concider other things.
Yeah, i agree.

B.

Dec 1 '06 #6
PaulR wrote:
fwiw.

I have a shell script that does this brute force method for our
Database of some 300+ Tables and it works just fine i.e the overhead
trying to set integrity where it's not required is miinimal.
Care to share? :)

B.

Dec 1 '06 #7
Brian Tkatch wrote:
[...]
Problem is, the number of tables you will have to set integrity on
might increase. Assume you have table T with status C. If you set
integrity on it, you will have to set integrity on tables dependent of it.

Because of that, i figured i didn't want to mess. I just want he script
to SET INTEGRITY on its own TABLEs, and on nothing else. So, if the
number increases outside of the listed TABLEs, the process itself is
flawed.
I did a simple test and perhaps the problem is less complicated than I
thought:

create table x.a (x int not null primary key);
create table x.b (x int not null primary key);
create table x.c (x int not null primary key);
create table x.d (x int not null primary key);
create table x.e (x int not null primary key);

alter table x.a add foreign key (x) references x.b;
alter table x.b add foreign key (x) references x.c;
alter table x.c add foreign key (x) references x.d;
alter table x.d add foreign key (x) references x.e;

-- make x.a check pending
load from /dev/null of ixf replace into x.e;

As expected x.e is now check pending.

[ltjn@lelles ~/src/integrity]$ db2 set integrity for x.e immediate
checked
SQL3601W The statement caused one or more tables to automatically be
placed
in the check pending state. SQLSTATE=01586
[ltjn@lelles ~/src/integrity]$ db2 "select tabname from syscat.tables
where status = 'C'"

TABNAME

--------------------------------------------------------------------------------------------------------------------------------
A

B

C

D
4 record(s) selected.

Now, that was a surprise for me. I thought that only X.D would be
check pending, but apparently DB2 is smart enough to cascade through
the graph. Hence, from here the set of "check pending" tables should
decrease. Can anyone confirm that this is true at all times, or could
it still happen that a new table is added to the set of check pending
tables?

Brian, as mentioned earlier I use the algorithm for a different
purpose, and perhaps it is way overkill for your problem. Sorry for any
confusion I may have caused

/Lennart

[...]

Dec 1 '06 #8
Lennart wrote:
Brian Tkatch wrote:
[...]
Problem is, the number of tables you will have to set integrity on
might increase. Assume you have table T with status C. If you set
integrity on it, you will have to set integrity on tables dependent of it.
Because of that, i figured i didn't want to mess. I just want he script
to SET INTEGRITY on its own TABLEs, and on nothing else. So, if the
number increases outside of the listed TABLEs, the process itself is
flawed.

I did a simple test and perhaps the problem is less complicated than I
thought:

create table x.a (x int not null primary key);
create table x.b (x int not null primary key);
create table x.c (x int not null primary key);
create table x.d (x int not null primary key);
create table x.e (x int not null primary key);

alter table x.a add foreign key (x) references x.b;
alter table x.b add foreign key (x) references x.c;
alter table x.c add foreign key (x) references x.d;
alter table x.d add foreign key (x) references x.e;

-- make x.a check pending
load from /dev/null of ixf replace into x.e;

As expected x.e is now check pending.

[ltjn@lelles ~/src/integrity]$ db2 set integrity for x.e immediate
checked
SQL3601W The statement caused one or more tables to automatically be
placed
in the check pending state. SQLSTATE=01586
[ltjn@lelles ~/src/integrity]$ db2 "select tabname from syscat.tables
where status = 'C'"

TABNAME

--------------------------------------------------------------------------------------------------------------------------------
A

B

C

D
4 record(s) selected.

Now, that was a surprise for me. I thought that only X.D would be
check pending, but apparently DB2 is smart enough to cascade through
the graph. Hence, from here the set of "check pending" tables should
decrease. Can anyone confirm that this is true at all times, or could
it still happen that a new table is added to the set of check pending
tables?

Brian, as mentioned earlier I use the algorithm for a different
purpose, and perhaps it is way overkill for your problem. Sorry for any
confusion I may have caused

/Lennart

[...]

Actually, the results you just displayed is what i expected. I cannot
test these things myself easily, as i do not have CREATE TABLE rights,
even on dev. :(

In my case, i loaded most of the TABLEs from production into
development (except for a few that are still in the works) and a
couple of those went into CHECK PENDING only after the SET INTEGRITY
statement (actually, i'm basing this on the resulting message of SET
INTEGRITY). I am not sure i fully iunderstand why. This should be the
equivalent to your case.

What i did just notice, however, is that i can SET INTEGRITY on
multiple TABLEs at the same time. And, at first look, as long as all of
the TABLEs can be set by that user, they indeed will be set. Could your
perchance test that for me? That is, using the example given above, do
a SET INTEGRITY FOR x.a, x.b, x.c, x.d, x.e IMMEDIATE CHECKED.

I think i shall write a query now to generate a statement to put
together a full SET INTEGRITY statement that includes:
1) TABLEs (Type = 'T')
2) in CHECK PENDING state (Status = 'C')
3) in a provided list ( (TabSchema, TabName) IN (list from file))

After it runs it, it will, need to SET INTEGRITY on any TABLEs that it
put into CHECK PENDING. The question now is, how does it know what it
put into CHECK PENDING? The two ideas i have are to take a snapshot
before and after the SET INTEGRITY statement. The other idea would be
to specifically check TABLEs that REFERENCE the TABLEs that were SET
(via SysCat.Referenc es).

B.

Dec 1 '06 #9

Brian Tkatch wrote:
[...]
Actually, the results you just displayed is what i expected. I cannot
test these things myself easily, as i do not have CREATE TABLE rights,
even on dev. :(
Check if you can install a personal developer edition on your
desktop.<duckIf you are unfortenate enough to run windows</duck>, you
could use cygwin :-)

[...]
>
What i did just notice, however, is that i can SET INTEGRITY on
multiple TABLEs at the same time. And, at first look, as long as all of
the TABLEs can be set by that user, they indeed will be set. Could your
perchance test that for me? That is, using the example given above, do
a SET INTEGRITY FOR x.a, x.b, x.c, x.d, x.e IMMEDIATE CHECKED.
Sure, given:

drop table x.a;
drop table x.b;
drop table x.c;
drop table x.d;
drop table x.e;

create table x.a (x int not null primary key);
create table x.b (x int not null primary key);
create table x.c (x int not null primary key);
create table x.d (x int not null primary key);
create table x.e (x int not null primary key);

alter table x.a add foreign key (x) references x.b;
alter table x.b add foreign key (x) references x.c;
alter table x.c add foreign key (x) references x.d;
alter table x.d add foreign key (x) references x.e;

-- make x.a check pending
load from /dev/null of ixf replace into x.e;

SET INTEGRITY FOR x.a, x.b, x.c, x.d, x.e IMMEDIATE CHECKED;

select tabname from syscat.tables where status = 'C';

returns:

TABNAME

--------------------------------------------------------------------------------------------------------------------------------

0 record(s) selected.

So that works indeed. I wasnt aware that one could specify several
tables, so I'll keep that in mind.
I think i shall write a query now to generate a statement to put
together a full SET INTEGRITY statement that includes:
1) TABLEs (Type = 'T')
2) in CHECK PENDING state (Status = 'C')
3) in a provided list ( (TabSchema, TabName) IN (list from file))

After it runs it, it will, need to SET INTEGRITY on any TABLEs that it
put into CHECK PENDING. The question now is, how does it know what it
put into CHECK PENDING? The two ideas i have are to take a snapshot
before and after the SET INTEGRITY statement. The other idea would be
to specifically check TABLEs that REFERENCE the TABLEs that were SET
(via SysCat.Referenc es).
Given the results above I would go for a brute force solution like:

while (true)
set integrity for <tables in check pendingimmediat e checked
if <tables in check pendingis empty
break

/Lennart

Dec 1 '06 #10

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

2
4318
by: trotter | last post by:
I want to know if there is a "best-practice" for setting up Database Maintenance Plans in SQL Server 7 or 2000. To be more specific, I want to know the order in which I complete the tasks. Do I complete optimization first, then integrity checks, then translog backup, then full backup??? OR is there a better order which should be used? Should I ALWAYS backup the transaction Log before I complete a full database backup, and if so, why?? ...
3
9057
by: RAD | last post by:
I am working with an evaluation copy of SQL Server 2000 for the first time; my DB experience lies with MS Access. I have a simple table in SQL Server (tblCompany) that has a field called "Ticker." When new company stock tickers (i.e., MSFT for Microsoft) are entered into the field, I'd like them in all caps--whether the user types msft, Msft, MsFt, etc. In Access, this was easy--simply set the Format to ">" in table design view. In...
2
2640
by: ezra epstein | last post by:
Hi, I've got a table: <code language="SQL"> CREATE TABLE "common"."dynamic_enum" ( "pk_id" integer DEFAULT nextval('"common"."pw_seq"') , "enum_type" common.non_empty_name
2
9968
by: Brice | last post by:
Hello, Sorry if this is a basic question but I can't seem to find the answer in the DB2 tutorial series or my DB2 manuals. How does one check the data integrity and referential integrity of an instance before running a backup? I see how one can run "db2ckbkp" after the backup has run, and I've seen some discussion of checksums in past postings, but what I'm looking for is more of: #!/bin/sh
10
2071
by: Shawn Chisholm | last post by:
Hi, I am trying to deal with a deadlock situation caused by foreign key references on insert and I was wondering if anyone knows what order the foreign keys are locked (or evaluated) in for a particular table? Deferring the locks is unfortunately not a good option for me... Thanks, Shawn ---------------------------(end of broadcast)--------------------------- TIP 5: Have you checked our extensive FAQ?
3
11082
by: Stephen | last post by:
This is probably something simple but I've been trying for a while now and can't seem to get it. I'm loading a table from an IXF file with the following command 'load from D:/db_scripts/load_test/nlm.ixf of ixf modified by USEDEFAULTS method n (NOTIFY_LIST_ID,PUBLICATION_ID) insert into mediaadm.NOTIFY_LIST_MEMBERS' this works fine but afterwards the table goes into a 'check pending'
1
5930
by: huyuhui | last post by:
The following is a question of LOAD utility. Question: How does the DB2 enforce table check constraints for data added to table with the LOAD utility? A. With the BUILD phase of LOAD B. With the SET INTEGRITY statement C. With the DELETE phase of the LOAD D. With the UPDATE CONSTRAINTS statement Answer is A
5
2577
by: Alan Little | last post by:
I have affiliates submitting batches of anywhere from 10 to several hundred orders. Each order in the batch must include an order ID, originated by the affiliate, which must be unique across all orders in all batches ever submitted by that affiliate. I'm trying to figure out the most efficient way to check the uniqueness of the order ID. Order data is being submitted to Zen Cart, and also stored in custom tables. I have created a unique...
6
10733
by: Hemant Shah | last post by:
Folks, One of our clients is performing an audit, and the auditor(s) asked following question, and I am not sure how to answer it: 28. Is there a control that prevents the corruption of databases (e.g. is there database integrity checking)? Please provide a description of the control and the name and phone number of the person who can demonstrate or validate the control.
0
7992
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
8400
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
1
8051
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
6725
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
0
5438
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
3940
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
1
2414
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
1
1505
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
0
1250
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.