[Last Call] Learn how to a build a cloud-first strategyRegister Now

x
?
Solved

Any way to hint at primary key without knowing it's name?

Posted on 2007-10-02
43
Medium Priority
?
531 Views
Last Modified: 2010-08-05
Dear Experts,

Ptjcb was kind enough to supply me with this syntax for hinting at an index:

SELECT * FROM MyTable WITH (INDEX (index_name) where MyField = ?...)

However, I don't know the NAME of the index.  It varies from site to site.  I do know it's always the primary key for the table, though.  Is there any way I can specifiy that?

I found this doc at the MS site:

"If a clustered index exists, INDEX(0) forces a clustered index scan and INDEX(1) forces a clustered index scan or seek. If no clustered index exists, INDEX(0) forces a table scan and INDEX(1) is interpreted as an error. "

Is INDEX(0) or INDEX(1) what I want?  Doc I saw elsewhere indicates it forces a table scan, which is the opposite of what I want.  Also, in this case, the primary key is clustered, but there is another clustered index also, which the db is already erroneously using to solve my query.  (That's the problem I'm trying to solve here...)

THANKS (AGAIN) !
BrianMc1958
0
Comment
Question by:BrianMc1958
  • 16
  • 11
  • 8
  • +3
43 Comments
 
LVL 15

Expert Comment

by:dbbishop
ID: 19999968
A primary key is USUALLY, but not always created as a clustered index. It is typically the best candidate for a clustered index on a table, if a clustered index is to be created, but is not always created as such. There are design considerations involved when deciding to make a primary key clustered or not. If the candidate key is not always going to be added in a logical order, and bulk inserts are going to be made, it may be decided not to cluster it, since creating a clusteed index will result in the database having to physically move a lot of data around. So, there is no guarentee that the primary key will always be a clustered index, that a clustered index will be on the primary key, or that a clustered index exists.
0
 

Author Comment

by:BrianMc1958
ID: 20000074
I own the table, and I know the primary key will always be clustered.  

Given that, do you know if I should use INDEX(0) or INDEX(1)?  Again, there is another clustered index that SQL Server is using instead of the primary key...
0
 
LVL 27

Expert Comment

by:ptjcb
ID: 20000102
>>Also, in this case, the primary key is clustered, but there is another clustered index also, which the db is already erroneously using to solve my query.

Wait...there is only one clustered index per table.
0
Granular recovery for Microsoft Exchange

With Veeam Explorer for Microsoft Exchange you can choose the Exchange Servers and restore points you’re interested in, and Veeam Explorer will present the contents of those mailbox stores for browsing, searching and exporting.

 
LVL 70

Expert Comment

by:Scott Pletcher
ID: 20000108
There can be only one clustered index per table.  If you need to force use of that index, you can use INDEX(1), since index #1 is always the clustered index.
0
 
LVL 15

Expert Comment

by:dbbishop
ID: 20000134
As ptjcb and ScottPletcher indicated (and you'd better listen to Scott), there can only be one clustered index on a table. If you know there is one, use INDEX(1)
0
 
LVL 143

Expert Comment

by:Guy Hengel [angelIII / a3]
ID: 20000179
now, do you REALLY need to "hint" to use an index?
in most cases, this is "useless"...

can you explain, why you need that?
if you use WHERE myfield = ?  , and myfield has an index, the index will be used unless the cardinality is "bad", or the statistics are out of date.

so, just get the proper index, and the stats up to date, and avoid using index hints ...
0
 
LVL 23

Assisted Solution

by:Racim BOUDJAKDJI
Racim BOUDJAKDJI earned 80 total points
ID: 20000294
<<now, do you REALLY need to "hint" to use an index?>>
I concur with angelIII's comment...hints are *poor man's tuning*...lots of efforts for relatively little gain...
0
 

Author Comment

by:BrianMc1958
ID: 20000297
>>Wait...there is only one clustered index per table
Sorry.  The other "clustered" index is an index consisting of two fields.  But you're all right.  It's not listed as "clustered".  My confusion.

>>can you explain, why you need that? if you use WHERE myfield = ?  , and myfield has an index, the index will be used unless the cardinality is "bad", or the statistics are out of date.
I don't know why it isn't being used.  It seems to happen at only one of a dozen customer sites.  I have tried updating the stats, and even reindexing, but no luck.

>>(and you'd better listen to Scott)
I do.  I do.

I'll try INDEX(1) over lunch.

Thanks...
0
 

Author Comment

by:BrianMc1958
ID: 20001222
Well, I'm afraid things got a little worse.  I added "WITH (INDEX = 1)" to my SELECT statement, and  I'm now getting clustered index scan.  My understanding is that that's very wrong, right?  I want "seek", not "scan", right?

I did not have the exact syntax, and my research elsewhere led me to "(INDEX = 1)" instead of the "INDEX(1)" shown above.  Is that the same?

This is the full plan, from a slightly different select.  (It's also referencing a TranCode field which has a separate index on it):

Execution Tree
--------------
Sort(ORDER BY:([FS_Vendor_Tran].[vt_TranDate] DESC, [FS_Vendor_Tran].[vt_TranSeq] DESC))
  |--Parallelism(Gather Streams)
       |--Filter(WHERE:(((((((like([FS_Vendor_Tran].[vt_TranCode], 'WD0 ', NULL) OR like([FS_Vendor_Tran].[vt_TranCode], 'WD7 ', NULL)) OR like([FS_Vendor_Tran].[vt_TranCode], 'WD8 ', NULL)) OR like([FS_Vendor_Tran].[vt_TranCode], 'WF0 ', NULL)) OR like([FS_Vendor_Tran].[vt_TranCode], 'CW0 ', NULL)) OR like([FS_Vendor_Tran].[vt_TranCode], 'CF0 ', NULL)) OR like([FS_Vendor_Tran].[vt_TranCode], 'CW0S', NULL)) OR like([FS_Vendor_Tran].[vt_TranCode], 'CF0S', NULL)))
            |--Clustered Index Scan(OBJECT:([FTG_Total].[dbo].[FS_Vendor_Tran].[PK__FS_Vendor_Tran_N__0397CBA8]), WHERE:((((([FS_Vendor_Tran].[vt_AcctNbr]=Convert([@P1]) AND [FS_Vendor_Tran].[vt_Appl]=Convert([@P2])) AND [FS_Vendor_Tran].[vt_BankID]=1) AND [FS_Vendor_Tran].[vt_TranDate]>=Convert([@P3])) AND [FS_Vendor_Tran].[vt_TranDate]<=Convert([@P6])) AND ([FS_Vendor_Tran].[vt_TranDate]<>Convert([@P4]) OR [FS_Vendor_Tran].[vt_TranSeq]>Convert([@P5]))))
0
 
LVL 143

Expert Comment

by:Guy Hengel [angelIII / a3]
ID: 20001699
>I did not have the exact syntax, and my research elsewhere led me to "(INDEX = 1)" instead of the "INDEX(1)" shown above.  Is that the same?
with SQL Server, INDEX(1) is the correct syntax.

>I don't know why it isn't being used.
well, it would be worth to try to understand the "why". putting a workaround without understanding is not a good idea.

what are the differences between the sites where it works fine and where it does not work fine:
* version / service pack level of sql server
* 1 CPU / multiple CPU on the server
* amount of rows in the table
* data type differences in the table (altered by the customer on it's site)
* ...

0
 

Author Comment

by:BrianMc1958
ID: 20001846
>>with SQL Server, INDEX(1) is the correct syntax.

With further research, I found "(INDEX = 1)" is older SQL Server syntax, limited to a single hint.  It appears to correctly specify that hint.  However, it's causing a scan on the index--not a seek.
 
>>well, it would be worth to try to understand the "why". putting a workaround without understanding is not a good idea.

I strongly agree.  But I'm afraid I'm about to start my sixth day on this single problem, and I'm getting a bit desperate.


I'm trying to look further into the difference between the sites.

In the mean time, if anyone has any more advice, I'd love to hear it.  The hint was used, but like I say, it caused a scan, not a seek, and therefore took even longer to run.  Is is reasonable to assume there is something, somehow wrong with my primary key?  Can it get corrupted somehow?  Would it help if I deleted it and rebuilt it by hand?  Should I toss myself under a bus?  
0
 
LVL 143

Expert Comment

by:Guy Hengel [angelIII / a3]
ID: 20001890
> Should I toss myself under a bus?  
that might help your "wife/husband" if you have good life insurance :)

> Is is reasonable to assume there is something, somehow wrong with my primary key?
something is wrong. what, well, I would wait for the results of the questions I tossed at you...

>Can it get corrupted somehow?  
yes. which is one of the questions: version/service pack -> if you have an unpatched sql server version, that could happen...

>Would it help if I deleted it and rebuilt it by hand?
it is not impossible that this can help.

0
 
LVL 70

Expert Comment

by:Scott Pletcher
ID: 20002246
If you don't specify a specific/range of *primary key* values *that SQL "knows" is a subset of the total rows available*, you will always get a "scan" instead of "seek".  It's likely that for the query you've specified, SQL cannot do a seek.  No hint in SQL Server will force it to use an unworkable approach (i.e. an approach that SQL itself would never have come up with).
0
 
LVL 15

Expert Comment

by:dbbishop
ID: 20002332
Might try to update statistics on the PK if that hasn't already been suggested. Maybe a shot in the dark, but definately less painful than a bus. Dropping and rebuilding index, as you suggested could be tried next.
0
 

Author Comment

by:BrianMc1958
ID: 20006082
>>If you don't specify a specific/range of *primary key* values *that SQL "knows" is a subset of the total rows available*, you will always get a "scan" instead of "seek".

In my research, I found one site that suggested that the Java PreparedStatement (similar to stored procedure) could actually be counterproductive, because the statement is prepared in advance, but with specifying the actual values passed in one set at a time later.  Is this what you're referring to?

Assume I have a table with primary clustered  key of KeyA, KeyB and KeyC.  And I have a PreparedStatement that says:

SELECT * FROM MyTable where KeyA = ? and KeyB = ? and (KeyC > ? and KeyC < ?)

That's pretty much what I'm doing.  Is it reasonable to think that that will always cause a scan?  I've been using PreparedStatements for a long time because they seem to generally double or triple response speed.  It would be a shock to find out that actually specifying primary key values causes degradation!
0
 
LVL 15

Expert Comment

by:dbbishop
ID: 20006263
>>Is it reasonable to think that that will always cause a scan?
No. SQL Server prepares an execution plan for any code it is to run. That execution plan is what decides which indexes to use, type of locks to initially set, and other hints. This can take anywhere fro sub-second to longer,, depending on the complexity of the query. In a stored procedure, the execution plan is calculated at the time the procedure is saved, and saved with the procedure, so SQL Server does not have to create an execution plan each time the procedure is run. Submitting a prepared statement as above will not prevent SQL Server from coming up with the same execution plan it would have if this was a stored procedure you were passing parameters to. It may just take a little longer (again, from milliseconds to seconds).
0
 
LVL 15

Assisted Solution

by:dbbishop
dbbishop earned 480 total points
ID: 20006310
You can 'try' a couple of things that have been mentioned above. I would do in following order (least to most time-consuming):
1) if transactions are being done through stored procedures (should only take a few seconds):
    exec sp_recompile dbo.myProcedure
2) update statistics on the table (from a few seconds to a couple of minutes, depending on table size)
    update statistics dbo.myTable with fullscan
3) drop and rebuild the primary key (could take considerable time depending on index size and table size)
0
 
LVL 70

Expert Comment

by:Scott Pletcher
ID: 20006746
>> SELECT * FROM MyTable where KeyA = ? and KeyB = ? and (KeyC > ? and KeyC < ?) <<

Your sample query plan looked like it had additional non-key cols.  

For that A,B,C query, I would have thought SQL would do a seek (ORDERED FORWARD).  If there's a clus index with C as the last column, that would seem to be an obvious access plan.
0
 

Author Comment

by:BrianMc1958
ID: 20006874
To dbbishop:

>> 1) if transactions are being done through stored procedures (should only take a few seconds):
    exec sp_recompile dbo.myProcedure

Not a stored procedure.  However, I did create a stripped-down Java class that does PreparedStatement exactly the same.  Run at my shop, it generates a seek.  Run at cust site, it generates a scan.

2) update statistics on the table (from a few seconds to a couple of minutes, depending on table size)
    update statistics dbo.myTable with fullscan

Did update stats much earlier.  No luck.  Haven't tried fullscan yet...

3) drop and rebuild the primary key (could take considerable time depending on index size and table size)

Just tried that, out of utter desperation.  No change.


TO ScottPletcher:

>>Your sample query plan looked like it had additional non-key cols.  

My first post did include other non-key cols.  I have since stripped it down to just key cols, but am still getting scan at cust site.

To anybosy:  I'm  now looking into Angellll's background suggestions:

what are the differences between the sites where it works fine and where it does not work fine:
* version / service pack level of sql server
* 1 CPU / multiple CPU on the server
* amount of rows in the table
* data type differences in the table (altered by the customer on it's site)
* ...

Any other help, as they say, would still be greatly appreciated.  I now have a quick unambiguous test I can run here and there, so that should help a lot.  If I can just figure out what to test...

Also, I usually say this at the end, but let me say it now in the middle:  I really appreciate all you folks taking so much time to help me out.  It's REALLY helping me out.


0
 

Author Comment

by:BrianMc1958
ID: 20006984
To Angellll:

Below, (works) = our shop, where it works, and (fails) = cust site, where it fails:

>>* version / service pack level of sql server
(works): 8.00.194 (RTM)  (fails): 8.00.2039 (SP4)
note: don't know what (RTM) means

>>* 1 CPU / multiple CPU on the server
(works): 1  (fails): 4

>>* amount of rows in the table
(works): 2 million  (fails): 6 million

>>* data type differences in the table (altered by the customer on it's site)
no differences in data types.
0
 

Author Comment

by:BrianMc1958
ID: 20007371
Have since tried update stats with full scan.  No luck...
0
 
LVL 15

Expert Comment

by:dbbishop
ID: 20007692
8.00.194 (RTM) is the original release to manufacturer with no service packs installed.
0
 
LVL 15

Expert Comment

by:dbbishop
ID: 20007780
I know you said you don't always know the name of the inndex, but what happens (for test purposes in this case) if you provide the index name instead of using INDEX(1) for the database that is failing. Will it still do a scan or does it do a seek?
0
 

Author Comment

by:BrianMc1958
ID: 20008087
I'll give it a shot.  Likely to be later this afternoon.

For those of you still keeping score at home, I've learned two more things:

At the (failing) cust site, I created a stored procedure which was similar to my PreparedStatement, and it generates a seek, not a scan.

In my shop, I also ran my mini-PreparedStatement against a 2005 SQL, and it also generates a seek, not a scan.

At this point, the most likely cause that I can see is that some 2000 SP introduced a bug handling PreparedStatements, and it was fixed by 2005.  However, that's still a guess at this point...
0
 

Author Comment

by:BrianMc1958
ID: 20009601
To dbbishop:

>>I know you said you don't always know the name of the inndex, but what happens (for test purposes in this case) if you provide the index name instead of using INDEX(1) for the database that is failing. Will it still do a scan or does it do a seek?

It took a while, but it's the same behavior if I name the index.  It does use the named index, but it does a scan, not a seek.


Anybody with any more ideas?  Has any of you ever actually thrown yourselves under a bus and found it to be a positive experience?
0
 
LVL 15

Assisted Solution

by:dbbishop
dbbishop earned 480 total points
ID: 20009683
Only if it is 120 degrees in the sun, the bus is the only shade in sight, and it is not running :-)
0
 

Author Comment

by:BrianMc1958
ID: 20009791
Thanks.  I'm passing these along to my wife.  She's interested in the insurance money.
0
 
LVL 15

Expert Comment

by:dbbishop
ID: 20009990
Let's try one more thing before giving up. Script the table from the two databases, including indexes and primary, foreign keys and post the DDL from both.

If you don't know how to do it, in EM, right-click on the table, and select All tasks.. > Generate SQL Scripts. Click on the Options tab and select Script indexes and Script PRIMARY keys, foreign keys. defaults and check constraints, then click on OK. Save both scripts and poste them in a reply.

Let's see if anything is different.
0
 

Author Comment

by:BrianMc1958
ID: 20017608
Hi folks.  After much more testing, I have narrowed down the problem much more.  It has to do with the precision of parameters passed into stored procedures--at least on SQL 2000 SP4.

To finally get SQL Server to use my primary key with index seek, I created this stripped-down sp:

CREATE PROCEDURE spVendorTran3 @acct numeric(10)  AS  SELECT * FROM FS_Vendor_Tran WHERE  vt_AcctNbr = @acct
GO

It works only if vt_AcctNbr is 10 bytes or less.  (Again, at least on SP4.)  If I increase the parameter to numeric(11), it does an indexscan.  Also, if I just say "numeric" without specifying a length.

The Java PreparedStatement I was originally using (which works fine on the original 2000, and on 2003) never specifies any length.

To me, this sure looks like a bug in that version of SQL Server.  What do you folks think?  (Is anybody listening to this wretched tale anymore?)

Thanks.

--BrianMc1958

 
0
 
LVL 70

Accepted Solution

by:
Scott Pletcher earned 1000 total points
ID: 20017707
>> To me, this sure looks like a bug in that version of SQL Server. <<

No, it is not a bug.  SQL is working as designed.  Datatypes are very important in query plans and in reusing them.  You want to make sure the datatypes in indexed columns do not have a different type/length from the values they're being compared to.

Sorry I didn't think of that earlier.
0
 
LVL 143

Expert Comment

by:Guy Hengel [angelIII / a3]
ID: 20017827
still listening...
interesting... I was aware that using the correct data type is important, but that on numeric data type the scale/precision would be important is new to me...

now, what if you casted in your procedure:

CREATE PROCEDURE spVendorTran3 @acct numeric(11)  AS  SELECT * FROM FS_Vendor_Tran WHERE  vt_AcctNbr = cast(@acct as numeric(10))

GO
0
 

Author Comment

by:BrianMc1958
ID: 20018039
Gotta go for the day.  Kind of amazed you guys are still listening.  Maybe I could say a bit more.

Although it's now clear the data length is actually critical at this particular site, it's very important for me to figure out how widespread this issue is.  My app uses Java PreparedStatement heavily, and there is literally no place in it to specify a length.  You don't even specify a type.  You just put in question marks.

I'm assuming SQL Server 2000 original version used to plug in the metadata for you that way.  Then some service pack changed that, so you had to be specific.  Then they changed it back (more or less) for 2003.

Here, on a 2000 box, I run:

CREATE PROCEDURE spVendorTran3 @acct numeric  AS  SELECT * FROM FS_Vendor_Tran WHERE  vt_AcctNbr = @acct
GO

without specifying a length at all.  It works just fine.  Returns immediately with index seek.  Same thing on 2003.

Do you folks know anything about my theory?  Did things change with a particular service pack?  Or possibly, is there some obscure switch within a particular SQL Server instance that would cause this behavior?

I need to run home and take my meds.  See you in the morning.  Thanks...
0
 
LVL 70

Expert Comment

by:Scott Pletcher
ID: 20018043
Yes, that seems to work also in the query plan.  I wasn't fully aware of this either until attending one of Kalen Delaney's sessions at PASS last month.
0
 
LVL 70

Expert Comment

by:Scott Pletcher
ID: 20018109
>> without specifying a length at all <<

That is still a very bad practice, of course.  SQL must provide a default length.  Perhaps on one release/SP the default will match your column, on another it will not.  

I say *always* specify a length for a datatype that uses one, even for varchar columns in conversions.  Since different defaults apply in different cases (for example, a CAST/CONVERT assumes length of 30 for unspecified VARCHAR(), whereas a DECLARE assumes length of 1), why give yourself and everyone else reading the code the headache of having to figure it out?  Just specify it specifically as you want it.
0
 
LVL 143

Expert Comment

by:Guy Hengel [angelIII / a3]
ID: 20018141
I have to concur with Scott on that last comment, especially the CAST/CONVERT vs DECLARE (and also the procedure parameter declaration) difference has already caused many people alot of headaches...

now, I do NOT know when sql server "fixed" this "bug" (I would have called that a feature LOL), but it shows again that you need to be careful. similar with the reserved keywords... why avoid using [] around field names, you never know what words will be put as reserved tomorrow ...
0
 
LVL 15

Expert Comment

by:dbbishop
ID: 20018587
Saved from the bus!!! Hope your wife doesn't miss the insurance money :-)
0
 
LVL 143

Assisted Solution

by:Guy Hengel [angelIII / a3]
Guy Hengel [angelIII / a3] earned 440 total points
ID: 20021492
I saw you just posted and deleted a question about this issue...

where I would have posted what I essentially posted already above:
CREATE PROCEDURE spVendorTran3 @acct numeric(11)  AS  SELECT * FROM FS_Vendor_Tran WHERE  vt_AcctNbr = cast(@acct as numeric(10))

ie in your java:
SELECT * FROM MyTable WITH (INDEX (index_name) where MyField = CAST( ? as numeric(10)) ...)
0
 

Author Comment

by:BrianMc1958
ID: 20021715
You're quick.  Yes.  I was cleaning up my next post and then realized you had already given me the answer.
0
 

Author Comment

by:BrianMc1958
ID: 20021781
To Everybody:

As is often the case, I'm overwhelmed by all your generosity in taking so much time to help me solve this.  It's been a nightmare tracking down exactly what the problem was, and then how to approach fixing it.  We were in very deep doo-doo here without all your help.  Again, I can't thank you enough.

--BrianMc1958  
0
 
LVL 15

Expert Comment

by:dbbishop
ID: 20021882
I figured the bus comments would get me some points. Thanks. :-)

"As is often the case, I'm overwhelmed by all your generosity in taking so much time to help me solve this...    We were in very deep doo-doo here without all your help.  Again, I can't thank you enough."

My sentiments exactly. I got back into programming a couple of years ago after a (non-voluntary) exit from the field for 3-1/2 years. I would not have made it back in without EE. Then I took a new job 3-months ago, going from App Developer to DB Developer. EE again came to the rescue.

I used EE strictly to ask question and search for results. One day, I stumbled upon a question from someone I knew the answer and posted it. The next day, I had 1,000 points. WOW! I learn just as much by looking through questions and doing my best to answer them than I could in almost any book. These are REAL WORLD scenarios with REAL WORLD problems and solutions, not something contrived for a text book. What better way to learn.

I've noticed several of the 'regulars' have participated in this question so I post this with full realization that they will see it and accept my thanks for being there as well as BrianMc1958's.
0
 
LVL 143

Expert Comment

by:Guy Hengel [angelIII / a3]
ID: 20021982
I am, let's say, a bit surprised by the choice of the accepted comments :)

seriously, my comment http://www.experts-exchange.com/Microsoft/Development/MS-SQL-Server/Q_22866805.html#20001699

indicated that you should look after, among others:
* data type differences in the table (altered by the customer on it's site)

and should have been in the list of accepted comments!

anyhow, glad we saved you from the bus :-)
0
 

Author Comment

by:BrianMc1958
ID: 20022269
To dbbishop:  That's great to hear.  My career has also been helped immeasurably by the good folks at EE.  And like Butch and Sundance being pursued by the Texas posse, I often turn around and wonder, "Who ARE those guys?"

To Angellll:  First, awarding points here took all my meager mathematical skills.  There weren't enough points to go around.  But what was causing me so much distress was that there was NO difference in the data types between the table there, where it failed, and the table here, where it worked.  Apparently, slightly different versions of SQL Server are simply treating them differently.  
0
 
LVL 143

Expert Comment

by:Guy Hengel [angelIII / a3]
ID: 20022337
>To Angellll:  First, awarding points here took all my meager mathematical skills.
lol.
did you ever try to split poinks in the lounge, 50 points on a question, among 34 comments of at least 14 different people ? ....

>that there was NO difference in the data types
ah, yes... point taken !
0

Featured Post

Free learning courses: Active Directory Deep Dive

Get a firm grasp on your IT environment when you learn Active Directory best practices with Veeam! Watch all, or choose any amount, of this three-part webinar series to improve your skills. From the basics to virtualization and backup, we got you covered.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Why is this different from all of the other step by step guides?  Because I make a living as a DBA and not as a writer and I lived through this experience. Defining the name: When I talk to people they say different names on this subject stuff l…
Recently we ran in to an issue while running some SQL jobs where we were trying to process the cubes.  We got an error saying failure stating 'NT SERVICE\SQLSERVERAGENT does not have access to Analysis Services. So this is a way to automate that wit…
Familiarize people with the process of retrieving data from SQL Server using an Access pass-thru query. Microsoft Access is a very powerful client/server development tool. One of the ways that you can retrieve data from a SQL Server is by using a pa…
Via a live example, show how to shrink a transaction log file down to a reasonable size.
Suggested Courses

825 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question